diff --git a/.env.example b/.env.example index ca9caca..80f4b84 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,19 @@ # Local Sibyl database. Keep this outside version control. ATTACKGRAPH_DB_PATH=.attackgraph/sibyl.db +ATTACKGRAPH_CONTROL_DB_PATH=.attackgraph/control.db ATTACKGRAPH_OPERATOR_ID=demo-operator +# Passkeys are offered but skippable in local mode. Use "passkey" to require them. +ATTACKGRAPH_AUTH_MODE=optional +ATTACKGRAPH_RP_ID=localhost +ATTACKGRAPH_ORIGIN=http://localhost:3000 + +# MCP clients created by the dashboard receive their own revocable value. +# ATTACKGRAPH_AGENT_TOKEN=atk_agent_... + # Optional H3RETIK execution gate. Quoting and planning do not require these. # ATTACKGRAPH_EXECUTION_APPROVAL_CODE=replace-with-a-human-generated-one-time-code +# ATTACKGRAPH_H3RETIK_ATTESTATION_TOKEN=separate-adapter-only-secret # H3RETIK_WALLET=0x... # H3RETIK_TOKEN=... # H3RETIK_SESSION_ID=... - diff --git a/.gitignore b/.gitignore index 4fc87dd..6f1b934 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,6 @@ __pycache__/ *.egg-info/ dist/ build/ +node_modules coverage.xml .coverage - diff --git a/README.md b/README.md index adc68c9..992421e 100644 --- a/README.md +++ b/README.md @@ -18,15 +18,15 @@ mix speculative hypotheses with confirmed findings. ATTACKGRAPH makes memory a load-bearing part of the loop: ```text -MCP agent - │ observations, attempts, action plans - ▼ -H1DR4 ATTACKGRAPH ─── Sibyl Memory - │ hot: target graph + current state - │ cold: append-only evidence and attempts - │ - ├── H1DR4 MCP discovery (capabilities) - └── H3RETIK (human-approved disposable Kali execution) +MCP agent ── typed semantic events ──▶ ATTACKGRAPH validator + │ +H3RETIK ── optional executor proof ─────────┤ + ▼ + Sibyl Memory + hot graph + cold event log + │ + ▼ + operator dashboard + MCP brief ``` The output is not a wall of notes. `attackgraph_get_brief` returns a compact, @@ -36,8 +36,9 @@ continue where the previous one stopped. The local ATTACKGRAPH dashboard gives the human operator the same shared brain: an interactive attack topology, confidence-separated intelligence, exhausted -paths, evidence chronology, H3RETIK action review, regressions, and JSON export. -It is read-only and binds locally by default. +paths, evidence chronology, per-worker attribution, H3RETIK session tracking, +regressions, and JSON export. It also manages passkeys, team invites, and +revocable MCP agent identities. It binds locally by default. ## Safety modes @@ -84,10 +85,47 @@ Example MCP configuration: Start with these MCP calls: 1. `attackgraph_open_engagement` -2. `attackgraph_record_observation` and `attackgraph_record_attempt` +2. `attackgraph_get_reporting_contract` once per fresh agent session 3. `attackgraph_get_brief` whenever the agent needs a compact state refresh 4. `attackgraph_request_action` before any active test -5. `attackgraph_create_regression` after a finding is confirmed +5. `attackgraph_report_event` after meaningful executions, attempts, findings, + loot, and checkpoints +6. `attackgraph_create_regression` after a finding is verified + +The agent supplies meaning; it does not self-certify proof. Agent reports are +`asserted`, H3RETIK results without action correlation are `attested`, and only +complete executor evidence tied to a scoped action is `verified`. See +[docs/TELEMETRY_V1.md](docs/TELEMETRY_V1.md) for the full contract and examples. + +### Evidence-derived engagement posture + +The dashboard headline is the current verified posture, never a suggested next +action or a team-authored status. Sibyl derives reconnaissance, mapped-surface, +confirmed-finding, and access-material states from high-confidence typed +telemetry. Hypotheses, job titles, and free-form text cannot change it. + +Higher-impact states require a successful, proof-bearing `finding.confirmed` +event submitted through `attackgraph_ingest_h3retik_event`. For example, its +attributes can declare the state supported by that proof: + +```json +{ + "event_type": "finding.confirmed", + "status": "completed", + "exit_code": 0, + "action_id": "act-example", + "attributes": {"posture_signal": "foothold_active"}, + "idempotency_key": "finding:fixture-shell" +} +``` + +The server attaches the H3RETIK proof reference and evidence digest; the agent +cannot set `verified` itself. The executor intake also requires a separate +adapter credential that is never included in agent MCP configurations. The +engine accepts `initial_access_established`, `foothold_active`, +`privileged_access`, `target_compromised`, `objective_complete`, and +`regression_detected`. Every displayed transition links back to its Sibyl +record, source, worker, and timestamp through **WHY THIS STATE**. ### Run the dashboard @@ -100,6 +138,39 @@ by `ATTACKGRAPH_DB_PATH` and the tenant selected by `ATTACKGRAPH_OPERATOR_ID`. Both services bind to the local machine; engagement data is not deployed to a hosted dashboard. +On first launch, claim the console with a passkey or continue in unclaimed +local mode. The browser delegates Touch ID, Face ID, Windows Hello, security +keys, and nearby-device QR to the operating system. ATTACKGRAPH stores the +public credential and a hashed browser-session token, never a password. + +### Connect an agent + +1. Open **IDENTITY** in the dashboard. +2. Create a named agent for the active engagement. +3. Copy the generated MCP configuration. Its token is shown once. +4. Add that configuration to any MCP-compatible host and restart the host. + +Each agent has an independent, revocable token. Its MCP process can only read +and write engagements where that agent has membership, and every observation, +hypothesis, attempt, action, and Sibyl event carries its agent identity. Do not +share the underlying H3RETIK credential with agents; ATTACKGRAPH remains the +broker and human approval boundary. + +The same panel creates single-use 24-hour human invite links and records which +H3RETIK session IDs belong to the engagement. The engagement ID is also the +durable H3RETIK workspace ID, so multiple disposable sessions contribute jobs +to one combined operation. Session bindings are operational metadata only; +H3RETIK wallet and access credentials stay in environment variables outside +the dashboard. + +For a locked deployment, set the relying-party values explicitly: + +```bash +ATTACKGRAPH_AUTH_MODE=passkey +ATTACKGRAPH_RP_ID=localhost +ATTACKGRAPH_ORIGIN=http://localhost:3000 +``` + ## Sibyl is the product, not a log sink Sibyl provides both sides of the attack brain: @@ -124,11 +195,18 @@ uv run pytest tests/test_memory.py -k deletion H3RETIK is the disposable execution plane, not the brain. The operator first accepts its terms and provisions a compute session outside ATTACKGRAPH. Then: -1. The agent drafts a command with `attackgraph_request_action`. -2. ATTACKGRAPH checks mode, exact target, lane, risk, and destructive patterns. -3. A human supplies the server-side approval code. -4. The adapter creates and starts a scoped job in the existing H3RETIK session. -5. Sanitized output returns to Sibyl as evidence and updates the graph. +1. Attach each paid session with `attackgraph_bind_h3retik_session`. +2. The agent drafts a command with `attackgraph_request_action` and selects a session. +3. ATTACKGRAPH checks mode, exact target, lane, risk, and destructive patterns. +4. A human supplies the server-side approval code. +5. The adapter creates and starts a scoped job in the selected H3RETIK session. +6. Sanitized output returns through `attackgraph_ingest_h3retik_event`; the + server computes a digest and promotes the matching Sibyl assertion in place. + +Sessions can be topped up without replacement. +`attackgraph_create_h3retik_extension_receipt` returns a Base funding address; +after the operator pays, `attackgraph_sync_h3retik_receipt` extends the same +session and its auth deadline. Credentials and approval codes are environment-only. They are never returned by an MCP tool or written to Sibyl. See [docs/H3RETIK_RUNBOOK.md](docs/H3RETIK_RUNBOOK.md). diff --git a/contracts-proofvault/H1DR4ProofVault.sol b/contracts-proofvault/H1DR4ProofVault.sol new file mode 100644 index 0000000..729449f --- /dev/null +++ b/contracts-proofvault/H1DR4ProofVault.sol @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +interface IERC20Exact { + function balanceOf(address account) external view returns (uint256); + function transfer(address to, uint256 amount) external returns (bool); + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} + +/// @notice USDC escrow and commitment layer for confidential vulnerability reports. +/// @dev Plaintext reports and decryption keys never enter this contract. Target ownership, +/// submission admission, validator verdicts, and key-release destinations are explicitly bound. +contract H1DR4ProofVault { + enum SubmissionStatus { COMMITTED, VALIDATED, REJECTED, REWARD_RESERVED, PAID, EXPIRED } + enum Severity { LOW, MEDIUM, HIGH, CRITICAL } + + struct Program { + address owner; + bytes32 targetHash; + bytes32 scopeHash; + uint64 authorizationEpoch; + bool active; + uint16 openSubmissions; + uint16 maxOpenSubmissions; + uint128 available; + uint128 locked; + uint128[4] rewards; + } + + struct Submission { + uint256 programId; + address researcher; + address owner; + bytes32 targetHash; + bytes32 reportCiphertextHash; + bytes32 reportCommitment; + bytes32 ownerKeyHash; + bytes32 verdictHash; + Severity severity; + SubmissionStatus status; + uint128 reservedMaximum; + uint128 reward; + uint64 submittedAt; + uint64 decisionDeadline; + uint64 authorizationEpoch; + uint32 validatorSetId; + bool exists; + } + + IERC20Exact public immutable paymentToken; + uint64 public immutable decisionWindow; + address public immutable governor; + bool public paused; + uint32 public currentValidatorSetId; + uint256 public nextProgramId = 1; + uint256 public nextSubmissionId = 1; + + mapping(uint32 => mapping(address => bool)) public validators; + mapping(uint32 => uint8) public validatorThresholds; + mapping(uint32 => bool) public validatorSetDisabled; + mapping(address => bytes32) public ownerKeyHashes; + mapping(bytes32 => address) public targetOwners; + mapping(bytes32 => uint64) public targetAuthorizationEpochs; + mapping(uint256 => Program) public programs; + mapping(uint256 => Submission) public submissions; + mapping(uint256 => mapping(address => bool)) public validatorVoted; + mapping(uint256 => mapping(bytes32 => uint8)) public verdictVotes; + mapping(uint256 => mapping(bytes32 => bool)) public usedCommitments; + mapping(bytes32 => uint64) public submissionPermits; + mapping(uint256 => uint256) public privatePool; + mapping(uint256 => mapping(address => uint256)) public privateContributions; + mapping(uint256 => bool) public keyReleaseCompleted; + + uint256 private entered; + + error Unauthorized(); + error InvalidInput(); + error InvalidState(); + error InsufficientEscrow(); + error TransferFailed(); + error DuplicateVote(); + error DuplicateCommitment(); + error MessageTooLarge(); + error Paused(); + + event GovernanceConfigured(address indexed governor); + event PauseChanged(bool paused); + event ValidatorSetConfigured(uint32 indexed validatorSetId, uint8 threshold, address[] validators); + event ValidatorSetDisabled(uint32 indexed validatorSetId); + event EncryptionKeyRegistered(address indexed owner, bytes32 indexed ownerKeyHash); + event TargetOwnerAuthorized( + bytes32 indexed targetHash, address indexed owner, uint64 authorizationEpoch + ); + event TargetOwnerRevoked( + bytes32 indexed targetHash, address indexed owner, uint64 authorizationEpoch + ); + event SubmissionAuthorized(bytes32 indexed permitDigest, uint64 expiresAt); + event SubmissionAuthorizationCancelled(bytes32 indexed permitDigest); + event ProgramCreated( + uint256 indexed programId, + address indexed owner, + bytes32 indexed targetHash, + bytes32 scopeHash, + uint16 maxOpenSubmissions + ); + event ProgramFunded(uint256 indexed programId, address indexed funder, uint256 amount); + event ProgramDeactivated(uint256 indexed programId); + event ProgramFundsWithdrawn(uint256 indexed programId, address indexed owner, uint256 amount); + event SubmissionCommitted( + uint256 indexed submissionId, + uint256 indexed programId, + address indexed researcher, + address owner, + bytes32 targetHash, + bytes32 reportCiphertextHash, + bytes32 reportCommitment, + uint64 decisionDeadline, + uint32 validatorSetId, + uint64 authorizationEpoch + ); + event PrivateSubmissionFunded( + uint256 indexed submissionId, address indexed funder, uint256 amount + ); + event PrivateContributionRefunded( + uint256 indexed submissionId, address indexed funder, uint256 amount + ); + event ValidatorVote( + uint256 indexed submissionId, + address indexed validator, + bytes32 indexed verdictDigest, + bool valid, + Severity severity, + bytes32 verdictHash + ); + event SubmissionValidated( + uint256 indexed submissionId, Severity severity, bytes32 verdictHash + ); + event SubmissionRejected(uint256 indexed submissionId, bytes32 verdictHash); + event SubmissionExpired(uint256 indexed submissionId); + event RewardReserved(uint256 indexed submissionId, address indexed researcher, uint256 amount); + event RewardPaid( + uint256 indexed submissionId, + address indexed researcher, + address indexed recipient, + uint256 amount + ); + event KeyReleaseDeferred(uint256 indexed submissionId, bytes32 indexed targetHash); + event ReportOwnerRebound( + uint256 indexed submissionId, + address indexed previousOwner, + address indexed currentOwner, + uint64 authorizationEpoch + ); + event KeyReleaseAuthorized( + uint256 indexed submissionId, address indexed owner, bytes32 indexed ownerKeyHash + ); + event EncryptedMessage( + uint256 indexed submissionId, + address indexed sender, + address indexed recipient, + bytes32 messageHash, + bytes ciphertext + ); + + modifier onlyGovernor() { + if (msg.sender != governor) revert Unauthorized(); + _; + } + + modifier whenNotPaused() { + if (paused) revert Paused(); + _; + } + + modifier nonReentrant() { + if (entered == 1) revert InvalidState(); + entered = 1; + _; + entered = 0; + } + + constructor( + address token, + address initialGovernor, + address[] memory initialValidators, + uint8 threshold, + uint64 initialDecisionWindow + ) { + if ( + token == address(0) || token.code.length == 0 || initialGovernor == address(0) + || initialGovernor.code.length == 0 || initialDecisionWindow < 1 hours + || initialDecisionWindow > 30 days + ) revert InvalidInput(); + paymentToken = IERC20Exact(token); + decisionWindow = initialDecisionWindow; + governor = initialGovernor; + _configureValidatorSet(initialValidators, threshold); + emit GovernanceConfigured(initialGovernor); + } + + function setPaused(bool nextPaused) external onlyGovernor { + paused = nextPaused; + emit PauseChanged(nextPaused); + } + + function configureValidatorSet(address[] calldata nextValidators, uint8 threshold) + external + onlyGovernor + returns (uint32 validatorSetId) + { + validatorSetId = _configureValidatorSet(nextValidators, threshold); + } + + function disableValidatorSet(uint32 validatorSetId) external onlyGovernor { + if (validatorThresholds[validatorSetId] == 0 || validatorSetDisabled[validatorSetId]) { + revert InvalidState(); + } + validatorSetDisabled[validatorSetId] = true; + emit ValidatorSetDisabled(validatorSetId); + } + + function registerEncryptionKey(bytes32 ownerKeyHash) external { + if (ownerKeyHash == bytes32(0)) revert InvalidInput(); + ownerKeyHashes[msg.sender] = ownerKeyHash; + emit EncryptionKeyRegistered(msg.sender, ownerKeyHash); + } + + function authorizeTargetOwner(bytes32 targetHash, address owner) external onlyGovernor { + if (targetHash == bytes32(0) || owner == address(0)) revert InvalidInput(); + if (targetOwners[targetHash] == owner) revert InvalidState(); + uint64 authorizationEpoch = ++targetAuthorizationEpochs[targetHash]; + targetOwners[targetHash] = owner; + emit TargetOwnerAuthorized(targetHash, owner, authorizationEpoch); + } + + function revokeTargetOwner(bytes32 targetHash) external onlyGovernor { + address owner = targetOwners[targetHash]; + if (owner == address(0)) revert InvalidState(); + delete targetOwners[targetHash]; + uint64 authorizationEpoch = ++targetAuthorizationEpochs[targetHash]; + emit TargetOwnerRevoked(targetHash, owner, authorizationEpoch); + } + + function submissionPermitDigest( + uint256 programId, + address researcher, + bytes32 reportCiphertextHash, + bytes32 reportCommitment + ) public view returns (bytes32) { + return keccak256( + abi.encode( + block.chainid, + address(this), + programId, + programs[programId].authorizationEpoch, + currentValidatorSetId, + decisionWindow, + researcher, + reportCiphertextHash, + reportCommitment + ) + ); + } + + function authorizeSubmission(bytes32 permitDigest, uint64 expiresAt) external onlyGovernor { + if (permitDigest == bytes32(0) || expiresAt <= block.timestamp) revert InvalidInput(); + submissionPermits[permitDigest] = expiresAt; + emit SubmissionAuthorized(permitDigest, expiresAt); + } + + function cancelSubmissionAuthorization(bytes32 permitDigest) external onlyGovernor { + if (submissionPermits[permitDigest] == 0) revert InvalidState(); + delete submissionPermits[permitDigest]; + emit SubmissionAuthorizationCancelled(permitDigest); + } + + function createProgram( + bytes32 targetHash, + bytes32 scopeHash, + uint128[4] calldata rewards, + uint16 maxOpenSubmissions + ) external returns (uint256 programId) { + if ( + targetHash == bytes32(0) || scopeHash == bytes32(0) + || targetOwners[targetHash] != msg.sender || maxOpenSubmissions == 0 + || maxOpenSubmissions > 64 + ) revert InvalidInput(); + bytes32 ownerKeyHash = ownerKeyHashes[msg.sender]; + if (ownerKeyHash == bytes32(0)) revert InvalidInput(); + if ( + rewards[0] == 0 || rewards[1] < rewards[0] || rewards[2] < rewards[1] + || rewards[3] < rewards[2] + ) revert InvalidInput(); + programId = nextProgramId++; + Program storage program = programs[programId]; + program.owner = msg.sender; + program.targetHash = targetHash; + program.scopeHash = scopeHash; + program.authorizationEpoch = targetAuthorizationEpochs[targetHash]; + program.active = true; + program.maxOpenSubmissions = maxOpenSubmissions; + program.rewards = rewards; + emit ProgramCreated(programId, msg.sender, targetHash, scopeHash, maxOpenSubmissions); + } + + function fundProgram(uint256 programId, uint128 amount) + external + whenNotPaused + nonReentrant + { + Program storage program = programs[programId]; + if (!program.active || amount == 0 || !_isProgramAuthorized(program)) { + revert InvalidState(); + } + _pullExact(msg.sender, amount); + program.available += amount; + emit ProgramFunded(programId, msg.sender, amount); + } + + function deactivateProgram(uint256 programId) external { + Program storage program = programs[programId]; + if (msg.sender != program.owner && msg.sender != governor) revert Unauthorized(); + if (!program.active) revert InvalidState(); + program.active = false; + emit ProgramDeactivated(programId); + } + + function withdrawProgramFunds(uint256 programId, uint128 amount) external nonReentrant { + Program storage program = programs[programId]; + if (msg.sender != program.owner) revert Unauthorized(); + if (program.active || amount == 0 || amount > program.available) revert InvalidState(); + program.available -= amount; + _pushExact(msg.sender, amount); + emit ProgramFundsWithdrawn(programId, msg.sender, amount); + } + + function submitToProgram( + uint256 programId, + bytes32 reportCiphertextHash, + bytes32 reportCommitment + ) external whenNotPaused returns (uint256 submissionId) { + Program storage program = programs[programId]; + if ( + !program.active || !_isProgramAuthorized(program) + || program.openSubmissions >= program.maxOpenSubmissions + ) { + revert InvalidState(); + } + if (usedCommitments[programId][reportCommitment]) revert DuplicateCommitment(); + bytes32 permitDigest = submissionPermitDigest( + programId, msg.sender, reportCiphertextHash, reportCommitment + ); + uint64 permitExpiry = submissionPermits[permitDigest]; + if (permitExpiry <= block.timestamp) revert Unauthorized(); + delete submissionPermits[permitDigest]; + usedCommitments[programId][reportCommitment] = true; + + uint128 maximum = program.rewards[uint256(Severity.CRITICAL)]; + if (program.available < maximum) revert InsufficientEscrow(); + program.available -= maximum; + program.locked += maximum; + ++program.openSubmissions; + submissionId = _commit( + programId, + msg.sender, + program.owner, + program.targetHash, + reportCiphertextHash, + reportCommitment, + maximum, + uint64(block.timestamp) + decisionWindow, + program.authorizationEpoch + ); + } + + function submitPrivate( + address owner, + bytes32 targetHash, + bytes32 reportCiphertextHash, + bytes32 reportCommitment, + uint64 refundAfter + ) external whenNotPaused returns (uint256 submissionId) { + if (owner == address(0) || owner == msg.sender || targetHash == bytes32(0)) { + revert InvalidInput(); + } + if (refundAfter < block.timestamp + 1 hours || refundAfter > block.timestamp + 30 days) { + revert InvalidInput(); + } + submissionId = _commit( + 0, + msg.sender, + owner, + targetHash, + reportCiphertextHash, + reportCommitment, + 0, + refundAfter, + 0 + ); + } + + function fundPrivateSubmission(uint256 submissionId, uint128 amount) + external + whenNotPaused + nonReentrant + { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists || submission.programId != 0 || amount == 0 + || block.timestamp >= submission.decisionDeadline + || ( + submission.status != SubmissionStatus.COMMITTED + && submission.status != SubmissionStatus.VALIDATED + ) + ) revert InvalidState(); + if (privatePool[submissionId] > type(uint128).max - amount) revert InsufficientEscrow(); + _pullExact(msg.sender, amount); + privatePool[submissionId] += amount; + privateContributions[submissionId][msg.sender] += amount; + emit PrivateSubmissionFunded(submissionId, msg.sender, amount); + } + + function refundPrivateContribution(uint256 submissionId) external nonReentrant { + Submission storage submission = submissions[submissionId]; + if (!submission.exists || submission.programId != 0) revert InvalidState(); + if ( + submission.status != SubmissionStatus.REJECTED + && submission.status != SubmissionStatus.EXPIRED + && block.timestamp < submission.decisionDeadline + ) revert InvalidState(); + if ( + submission.status == SubmissionStatus.REWARD_RESERVED + || submission.status == SubmissionStatus.PAID + ) revert InvalidState(); + uint256 amount = privateContributions[submissionId][msg.sender]; + if (amount == 0) revert InvalidState(); + privateContributions[submissionId][msg.sender] = 0; + privatePool[submissionId] -= amount; + _pushExact(msg.sender, amount); + emit PrivateContributionRefunded(submissionId, msg.sender, amount); + } + + function attest( + uint256 submissionId, + bool valid, + Severity severity, + bytes32 verdictHash + ) external { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists || submission.status != SubmissionStatus.COMMITTED + || block.timestamp >= submission.decisionDeadline || verdictHash == bytes32(0) + || validatorSetDisabled[submission.validatorSetId] + || !validators[submission.validatorSetId][msg.sender] + ) revert InvalidState(); + if (validatorVoted[submissionId][msg.sender]) revert DuplicateVote(); + if ( + submission.programId != 0 + && !_isProgramAuthorized(programs[submission.programId]) + ) revert Unauthorized(); + validatorVoted[submissionId][msg.sender] = true; + bytes32 verdictDigest = keccak256(abi.encode(valid, severity, verdictHash)); + uint8 count = ++verdictVotes[submissionId][verdictDigest]; + emit ValidatorVote(submissionId, msg.sender, verdictDigest, valid, severity, verdictHash); + if (count < validatorThresholds[submission.validatorSetId]) return; + + submission.verdictHash = verdictHash; + submission.severity = severity; + if (!valid) { + submission.status = SubmissionStatus.REJECTED; + _releaseFundedMaximum(submission); + _closeFundedSubmission(submission); + emit SubmissionRejected(submissionId, verdictHash); + return; + } + submission.status = SubmissionStatus.VALIDATED; + emit SubmissionValidated(submissionId, severity, verdictHash); + if (submission.programId != 0) { + _reserveFundedReward(submissionId, submission); + _closeFundedSubmission(submission); + } + } + + function expireSubmission(uint256 submissionId) external { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists || block.timestamp < submission.decisionDeadline + || ( + submission.status != SubmissionStatus.COMMITTED + && submission.status != SubmissionStatus.VALIDATED + ) + ) revert InvalidState(); + submission.status = SubmissionStatus.EXPIRED; + if (submission.programId != 0) { + _releaseFundedMaximum(submission); + _closeFundedSubmission(submission); + } + emit SubmissionExpired(submissionId); + } + + function authorizePrivatePayout(uint256 submissionId) external { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists || submission.programId != 0 || msg.sender != submission.owner + ) revert Unauthorized(); + if ( + submission.status != SubmissionStatus.VALIDATED + || block.timestamp >= submission.decisionDeadline + ) revert InvalidState(); + uint256 amount = privatePool[submissionId]; + if (amount == 0 || amount > type(uint128).max) revert InsufficientEscrow(); + bytes32 ownerKeyHash = ownerKeyHashes[msg.sender]; + if (ownerKeyHash == bytes32(0)) revert InvalidInput(); + submission.ownerKeyHash = ownerKeyHash; + submission.reward = uint128(amount); + submission.status = SubmissionStatus.REWARD_RESERVED; + emit RewardReserved(submissionId, submission.researcher, amount); + } + + function claimReward(uint256 submissionId) external nonReentrant { + _claimReward(submissionId, msg.sender); + } + + /// @notice Claims an earned reward to a researcher-selected recipient. + /// @dev This preserves liveness if the payment token cannot transfer to the researcher's + /// address. Only the immutable submission researcher can choose the payout recipient. + function claimRewardTo(uint256 submissionId, address recipient) external nonReentrant { + if (recipient == address(0)) revert InvalidInput(); + _claimReward(submissionId, recipient); + } + + function _claimReward(uint256 submissionId, address recipient) internal { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists || msg.sender != submission.researcher + || submission.status != SubmissionStatus.REWARD_RESERVED + || submission.reward == 0 + ) revert InvalidState(); + uint128 amount = submission.reward; + submission.status = SubmissionStatus.PAID; + if (submission.programId != 0) { + programs[submission.programId].locked -= amount; + } else { + privatePool[submissionId] = 0; + } + _pushExact(recipient, amount); + emit RewardPaid(submissionId, msg.sender, recipient, amount); + if (_isSubmissionReleaseAuthorized(submission)) { + _authorizeKeyRelease(submissionId, submission); + } else { + emit KeyReleaseDeferred(submissionId, submission.targetHash); + } + } + + function rebindFundedReportOwner(uint256 submissionId) external onlyGovernor { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists || submission.programId == 0 || keyReleaseCompleted[submissionId] + || ( + submission.status != SubmissionStatus.REWARD_RESERVED + && submission.status != SubmissionStatus.PAID + ) + ) revert InvalidState(); + address currentOwner = targetOwners[submission.targetHash]; + uint64 authorizationEpoch = targetAuthorizationEpochs[submission.targetHash]; + bytes32 currentKeyHash = ownerKeyHashes[currentOwner]; + if (currentOwner == address(0) || currentKeyHash == bytes32(0)) revert InvalidInput(); + address previousOwner = submission.owner; + submission.owner = currentOwner; + submission.authorizationEpoch = authorizationEpoch; + submission.ownerKeyHash = currentKeyHash; + emit ReportOwnerRebound( + submissionId, previousOwner, currentOwner, authorizationEpoch + ); + if (submission.status == SubmissionStatus.PAID) { + _authorizeKeyRelease(submissionId, submission); + } + } + + function sendEncryptedMessage(uint256 submissionId, bytes calldata ciphertext) external { + Submission storage submission = submissions[submissionId]; + if ( + !submission.exists + || (msg.sender != submission.researcher && msg.sender != submission.owner) + ) revert Unauthorized(); + if (ciphertext.length == 0) revert InvalidInput(); + if (ciphertext.length > 2048) revert MessageTooLarge(); + address recipient = + msg.sender == submission.researcher ? submission.owner : submission.researcher; + emit EncryptedMessage( + submissionId, msg.sender, recipient, keccak256(ciphertext), ciphertext + ); + } + + function _configureValidatorSet(address[] memory nextValidators, uint8 threshold) + internal + returns (uint32 validatorSetId) + { + if ( + nextValidators.length < 2 || nextValidators.length > 32 || threshold < 2 + || threshold > nextValidators.length + ) revert InvalidInput(); + validatorSetId = ++currentValidatorSetId; + validatorThresholds[validatorSetId] = threshold; + for (uint256 index; index < nextValidators.length; ++index) { + address validator = nextValidators[index]; + if (validator == address(0) || validators[validatorSetId][validator]) { + revert InvalidInput(); + } + validators[validatorSetId][validator] = true; + } + emit ValidatorSetConfigured(validatorSetId, threshold, nextValidators); + } + + function _commit( + uint256 programId, + address researcher, + address owner, + bytes32 targetHash, + bytes32 reportCiphertextHash, + bytes32 reportCommitment, + uint128 reservedMaximum, + uint64 decisionDeadline, + uint64 authorizationEpoch + ) internal returns (uint256 submissionId) { + if ( + reportCiphertextHash == bytes32(0) || reportCommitment == bytes32(0) + || decisionDeadline <= block.timestamp + || validatorSetDisabled[currentValidatorSetId] + ) revert InvalidInput(); + submissionId = nextSubmissionId++; + bytes32 ownerKeyHash = ownerKeyHashes[owner]; + submissions[submissionId] = Submission({ + programId: programId, + researcher: researcher, + owner: owner, + targetHash: targetHash, + reportCiphertextHash: reportCiphertextHash, + reportCommitment: reportCommitment, + ownerKeyHash: ownerKeyHash, + verdictHash: bytes32(0), + severity: Severity.LOW, + status: SubmissionStatus.COMMITTED, + reservedMaximum: reservedMaximum, + reward: 0, + submittedAt: uint64(block.timestamp), + decisionDeadline: decisionDeadline, + authorizationEpoch: authorizationEpoch, + validatorSetId: currentValidatorSetId, + exists: true + }); + emit SubmissionCommitted( + submissionId, + programId, + researcher, + owner, + targetHash, + reportCiphertextHash, + reportCommitment, + decisionDeadline, + currentValidatorSetId, + authorizationEpoch + ); + } + + function _isProgramAuthorized(Program storage program) internal view returns (bool) { + return targetOwners[program.targetHash] == program.owner + && targetAuthorizationEpochs[program.targetHash] == program.authorizationEpoch; + } + + function _isSubmissionReleaseAuthorized(Submission storage submission) + internal + view + returns (bool) + { + if (submission.programId == 0) return true; + return targetOwners[submission.targetHash] == submission.owner + && targetAuthorizationEpochs[submission.targetHash] == submission.authorizationEpoch; + } + + function _authorizeKeyRelease(uint256 submissionId, Submission storage submission) internal { + if (keyReleaseCompleted[submissionId]) revert InvalidState(); + bytes32 releaseKeyHash = ownerKeyHashes[submission.owner]; + if (releaseKeyHash == bytes32(0)) revert InvalidInput(); + submission.ownerKeyHash = releaseKeyHash; + keyReleaseCompleted[submissionId] = true; + emit KeyReleaseAuthorized(submissionId, submission.owner, releaseKeyHash); + } + + function _reserveFundedReward(uint256 submissionId, Submission storage submission) internal { + Program storage program = programs[submission.programId]; + uint128 reward = program.rewards[uint256(submission.severity)]; + uint128 difference = submission.reservedMaximum - reward; + program.locked -= difference; + program.available += difference; + submission.reservedMaximum = reward; + submission.reward = reward; + submission.status = SubmissionStatus.REWARD_RESERVED; + emit RewardReserved(submissionId, submission.researcher, reward); + } + + function _releaseFundedMaximum(Submission storage submission) internal { + if (submission.programId == 0 || submission.reservedMaximum == 0) return; + Program storage program = programs[submission.programId]; + program.locked -= submission.reservedMaximum; + program.available += submission.reservedMaximum; + submission.reservedMaximum = 0; + } + + function _closeFundedSubmission(Submission storage submission) internal { + if (submission.programId == 0) return; + Program storage program = programs[submission.programId]; + if (program.openSubmissions == 0) revert InvalidState(); + --program.openSubmissions; + } + + function _pullExact(address from, uint256 amount) internal { + uint256 beforeBalance = paymentToken.balanceOf(address(this)); + _callToken(abi.encodeCall(IERC20Exact.transferFrom, (from, address(this), amount))); + uint256 afterBalance = paymentToken.balanceOf(address(this)); + if (afterBalance < beforeBalance || afterBalance - beforeBalance != amount) { + revert TransferFailed(); + } + } + + function _pushExact(address to, uint256 amount) internal { + uint256 vaultBefore = paymentToken.balanceOf(address(this)); + uint256 recipientBefore = paymentToken.balanceOf(to); + _callToken(abi.encodeCall(IERC20Exact.transfer, (to, amount))); + uint256 vaultAfter = paymentToken.balanceOf(address(this)); + uint256 recipientAfter = paymentToken.balanceOf(to); + if ( + vaultAfter > vaultBefore || vaultBefore - vaultAfter != amount + || recipientAfter < recipientBefore || recipientAfter - recipientBefore != amount + ) revert TransferFailed(); + } + + function _callToken(bytes memory payload) internal { + (bool ok, bytes memory result) = address(paymentToken).call(payload); + if ( + !ok || (result.length != 0 && result.length != 32) + || (result.length == 32 && !abi.decode(result, (bool))) + ) revert TransferFailed(); + } +} diff --git a/contracts-proofvault/README.md b/contracts-proofvault/README.md new file mode 100644 index 0000000..5faf497 --- /dev/null +++ b/contracts-proofvault/README.md @@ -0,0 +1,118 @@ +# H1DR4 ProofVault contracts + +`H1DR4ProofVault.sol` is the escrow and public commitment layer for confidential +vulnerability reports. The contract never receives report plaintext or a +decryption key. It stores commitments, admission permits, validator decisions, +escrow state, and encrypted chat events. + +## Trust model + +- The governor is an immutable Safe contract wallet from the first block. It + authorizes target owners and exact funded-submission digests, rotates validator + sets, can disable a compromised set, pauses new funding and submissions, and + can deactivate a program. Safe owners can rotate under the Safe threshold, but + the vault cannot later be pointed at a weaker governor. +- Every target authorization has a monotonically increasing epoch. Programs and + permits bind that epoch, so revocation or reassignment invalidates stale + funding, submission, and validator paths without iterating over old programs. +- Every validator set has at least two distinct validators and a threshold of at + least two. Each submission snapshots one validator set. Changing the current set cannot + rewrite an active or finalized submission; disabling a compromised set stops + its votes and the submission can expire safely. +- A funded submission needs a one-use permit bound to chain ID, this contract, + the program authorization epoch, current validator set, decision window, + researcher, ciphertext hash, and report commitment. Duplicate commitments + and excess pending submissions are rejected. The governor may cancel a permit + before it is consumed. +- Target ownership is a governor-approved on-chain mapping. The portal must + complete the real-world ownership check before calling `authorizeTargetOwner`. +- The payment token must transfer exact amounts. Incoming and outgoing balance + deltas are checked before escrow credit or a key-release signal is accepted. + +The release script accepts only allowlisted official Safe singleton, proxy, and +fallback-handler runtime hashes. At the release block the Safe must be at least +2-of-N and have no modules, guard, or module guard. This governance model is +intentionally conservative for the first mainnet beta. +A later release can replace on-chain permit transactions with expiring EIP-712 +permits while preserving the same digest and replay invariants. + +## State transitions + +```text +funded: COMMITTED -> REWARD_RESERVED -> PAID + \-> REJECTED + \-> EXPIRED + +private: COMMITTED -> VALIDATED -> owner authorizes -> REWARD_RESERVED -> PAID + \-> REJECTED / EXPIRED -> contributor refunds +``` + +Funded submission admission locks the configured critical reward. Validation +retains only the assessed reward; rejection or deadline expiry returns the full +reservation. `openSubmissions` is decremented exactly once at those terminal +validator/expiry transitions. + +Private pools accept contributions only before their deadline. The named owner +must authorize a validated payout before that deadline; otherwise contributors +can refund and anyone can mark the submission expired. + +`RewardPaid` and report-key release are deliberately separate. A researcher can +claim an earned funded reward after target-owner revocation, but the claim emits +`KeyReleaseDeferred` instead of releasing the report. The governor can later +call `rebindFundedReportOwner` only to the target's currently authorized owner; +an already-paid report is then released exactly once. Private reports keep their +explicit owner and release normally after exact payment. + +If USDC cannot transfer to the researcher's original address, only that +researcher may call `claimRewardTo` and select a different nonzero recipient. +The report owner and key-release destination do not change with the payout route. + +`KeyReleaseAuthorized` is emitted only after exact payout and a current target +authorization (or after a safe paid-report rebind). At release time the contract +refreshes the current owner's registered key hash. The off-chain release worker +must still wait for finality and verify chain ID, contract, payment token, +submission, target authorization epoch, recipient, amount, and owner key hash. + +`sendEncryptedMessage` publishes ciphertext and metadata in a permanent public +event. Clients must use randomized authenticated encryption locally. Encoding +plaintext as hex is not encryption. + +## Compile + +The release compiler is `solc` 0.8.33 with the `paris` EVM target, optimizer +runs set to 200, and IR compilation enabled. Run from this directory: + +```bash +npm ci +npm run compile +npm test +npm run attest:build +``` + +`SOLJSON_PATH` is forbidden. Compilation uses the lockfile-pinned compiler before +any signer secret is introduced. `attest:build` performs two clean installs and +requires their artifacts to match the release artifact byte-for-byte. Release +receipts bind externally reviewed source, artifact, reproducible-build, and +security-snapshot digests; the compiler settings; constructor arguments; creation +bytecode; deployed runtime; transaction hash; and post-deployment readback. +Immutable byte ranges are masked when comparing deployed code with the template. + +The Base release path is deliberately narrow: `https://mainnet.base.org/` is +corroborated by `https://base-mainnet.public.blastapi.io/`, redirects are rejected, +the same finalized block and pending nonce must agree, and a confirmed deployment +is not sealed until both endpoints report the deployment block finalized. A +broadcast journal remains on disk if mining, finality, or readback fails. + +## Mainnet release gate + +Do not fund a deployment until all of the following are attached to one receipt: + +1. a complete security scan of the exact source; +2. local EVM state-transition and adversarial-token tests; +3. verified Base chain ID and canonical USDC address; +4. an independently verified immutable Safe governor, validator addresses, + threshold, and deadline policy; +5. an external source/artifact digest plus the clean-build attestation digest; +6. verified finalized runtime bytecode and constructor arguments; +7. H3RETIK job, Sibyl evidence, and notification receipts bound to the same + workspace and engagement. diff --git a/contracts-proofvault/artifacts/H1DR4ProofVault.build.json b/contracts-proofvault/artifacts/H1DR4ProofVault.build.json new file mode 100644 index 0000000..25891f6 --- /dev/null +++ b/contracts-proofvault/artifacts/H1DR4ProofVault.build.json @@ -0,0 +1,1815 @@ +{ + "schema": "h1dr4.proofvault-build/v1", + "contract": "H1DR4ProofVault", + "compiler": "0.8.33+commit.64118f21.Emscripten.clang", + "settings": { + "evmVersion": "paris", + "viaIR": true, + "optimizer": { + "enabled": true, + "runs": 200 + } + }, + "source_sha256": "a18f95c1f3023e455ad3a0a6b282ffa6d7dd6f539a0b56e0528e2d64935473e2", + "abi_entries": 82, + "creation_bytecode_bytes": 15435, + "creation_bytecode_sha256": "eb0c2f14d95a42e49323c516e76c8d9d0f403e4d2006735fdaff3371391850fa", + "runtime_template_bytes": 14316, + "runtime_template_sha256": "4296adaaa38b40b23787b6d78b9fb0bb8a4416ddf97d77b49f77c3fd66dd16de", + "runtime_immutable_references": { + "105": [ + { + "length": 32, + "start": 9302 + }, + { + "length": 32, + "start": 12118 + }, + { + "length": 32, + "start": 13265 + }, + { + "length": 32, + "start": 13955 + } + ], + "107": [ + { + "length": 32, + "start": 6297 + }, + { + "length": 32, + "start": 6546 + }, + { + "length": 32, + "start": 7089 + }, + { + "length": 32, + "start": 7237 + }, + { + "length": 32, + "start": 8975 + }, + { + "length": 32, + "start": 10923 + } + ], + "109": [ + { + "length": 32, + "start": 556 + }, + { + "length": 32, + "start": 818 + }, + { + "length": 32, + "start": 3217 + }, + { + "length": 32, + "start": 4059 + }, + { + "length": 32, + "start": 5624 + }, + { + "length": 32, + "start": 8367 + }, + { + "length": 32, + "start": 9083 + }, + { + "length": 32, + "start": 9919 + }, + { + "length": 32, + "start": 10103 + }, + { + "length": 32, + "start": 10281 + } + ] + }, + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "initialGovernor", + "type": "address" + }, + { + "internalType": "address[]", + "name": "initialValidators", + "type": "address[]" + }, + { + "internalType": "uint8", + "name": "threshold", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "initialDecisionWindow", + "type": "uint64" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "DuplicateCommitment", + "type": "error" + }, + { + "inputs": [], + "name": "DuplicateVote", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientEscrow", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInput", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidState", + "type": "error" + }, + { + "inputs": [], + "name": "MessageTooLarge", + "type": "error" + }, + { + "inputs": [], + "name": "Paused", + "type": "error" + }, + { + "inputs": [], + "name": "TransferFailed", + "type": "error" + }, + { + "inputs": [], + "name": "Unauthorized", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "messageHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "ciphertext", + "type": "bytes" + } + ], + "name": "EncryptedMessage", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "ownerKeyHash", + "type": "bytes32" + } + ], + "name": "EncryptionKeyRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "governor", + "type": "address" + } + ], + "name": "GovernanceConfigured", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "ownerKeyHash", + "type": "bytes32" + } + ], + "name": "KeyReleaseAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + } + ], + "name": "KeyReleaseDeferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "PauseChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "PrivateContributionRefunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "PrivateSubmissionFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "scopeHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint16", + "name": "maxOpenSubmissions", + "type": "uint16" + } + ], + "name": "ProgramCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "programId", + "type": "uint256" + } + ], + "name": "ProgramDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "funder", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProgramFunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ProgramFundsWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "currentOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationEpoch", + "type": "uint64" + } + ], + "name": "ReportOwnerRebound", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "researcher", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "RewardPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "researcher", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "RewardReserved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "permitDigest", + "type": "bytes32" + } + ], + "name": "SubmissionAuthorizationCancelled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "permitDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "expiresAt", + "type": "uint64" + } + ], + "name": "SubmissionAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "researcher", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "reportCiphertextHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "reportCommitment", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "decisionDeadline", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "validatorSetId", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationEpoch", + "type": "uint64" + } + ], + "name": "SubmissionCommitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "name": "SubmissionExpired", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "verdictHash", + "type": "bytes32" + } + ], + "name": "SubmissionRejected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum H1DR4ProofVault.Severity", + "name": "severity", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "verdictHash", + "type": "bytes32" + } + ], + "name": "SubmissionValidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationEpoch", + "type": "uint64" + } + ], + "name": "TargetOwnerAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "authorizationEpoch", + "type": "uint64" + } + ], + "name": "TargetOwnerRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "validatorSetId", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "threshold", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "validators", + "type": "address[]" + } + ], + "name": "ValidatorSetConfigured", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint32", + "name": "validatorSetId", + "type": "uint32" + } + ], + "name": "ValidatorSetDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "validator", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "verdictDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bool", + "name": "valid", + "type": "bool" + }, + { + "indexed": false, + "internalType": "enum H1DR4ProofVault.Severity", + "name": "severity", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "verdictHash", + "type": "bytes32" + } + ], + "name": "ValidatorVote", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "valid", + "type": "bool" + }, + { + "internalType": "enum H1DR4ProofVault.Severity", + "name": "severity", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "verdictHash", + "type": "bytes32" + } + ], + "name": "attest", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "name": "authorizePrivatePayout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "permitDigest", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "expiresAt", + "type": "uint64" + } + ], + "name": "authorizeSubmission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "authorizeTargetOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "permitDigest", + "type": "bytes32" + } + ], + "name": "cancelSubmissionAuthorization", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "name": "claimReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "claimRewardTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "nextValidators", + "type": "address[]" + }, + { + "internalType": "uint8", + "name": "threshold", + "type": "uint8" + } + ], + "name": "configureValidatorSet", + "outputs": [ + { + "internalType": "uint32", + "name": "validatorSetId", + "type": "uint32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "scopeHash", + "type": "bytes32" + }, + { + "internalType": "uint128[4]", + "name": "rewards", + "type": "uint128[4]" + }, + { + "internalType": "uint16", + "name": "maxOpenSubmissions", + "type": "uint16" + } + ], + "name": "createProgram", + "outputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "currentValidatorSetId", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + } + ], + "name": "deactivateProgram", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decisionWindow", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "validatorSetId", + "type": "uint32" + } + ], + "name": "disableValidatorSet", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "name": "expireSubmission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + } + ], + "name": "fundPrivateSubmission", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + } + ], + "name": "fundProgram", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "governor", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "keyReleaseCompleted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextProgramId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "nextSubmissionId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "ownerKeyHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paymentToken", + "outputs": [ + { + "internalType": "contract IERC20Exact", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "privateContributions", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "privatePool", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "programs", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "scopeHash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "authorizationEpoch", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "internalType": "uint16", + "name": "openSubmissions", + "type": "uint16" + }, + { + "internalType": "uint16", + "name": "maxOpenSubmissions", + "type": "uint16" + }, + { + "internalType": "uint128", + "name": "available", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "locked", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "name": "rebindFundedReportOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "name": "refundPrivateContribution", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "ownerKeyHash", + "type": "bytes32" + } + ], + "name": "registerEncryptionKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + } + ], + "name": "revokeTargetOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "ciphertext", + "type": "bytes" + } + ], + "name": "sendEncryptedMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "nextPaused", + "type": "bool" + } + ], + "name": "setPaused", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "researcher", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "reportCiphertextHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "reportCommitment", + "type": "bytes32" + } + ], + "name": "submissionPermitDigest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "submissionPermits", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "submissions", + "outputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "researcher", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "reportCiphertextHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "reportCommitment", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "ownerKeyHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "verdictHash", + "type": "bytes32" + }, + { + "internalType": "enum H1DR4ProofVault.Severity", + "name": "severity", + "type": "uint8" + }, + { + "internalType": "enum H1DR4ProofVault.SubmissionStatus", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "reservedMaximum", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "reward", + "type": "uint128" + }, + { + "internalType": "uint64", + "name": "submittedAt", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "decisionDeadline", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "authorizationEpoch", + "type": "uint64" + }, + { + "internalType": "uint32", + "name": "validatorSetId", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "exists", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "targetHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "reportCiphertextHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "reportCommitment", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "refundAfter", + "type": "uint64" + } + ], + "name": "submitPrivate", + "outputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "reportCiphertextHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "reportCommitment", + "type": "bytes32" + } + ], + "name": "submitToProgram", + "outputs": [ + { + "internalType": "uint256", + "name": "submissionId", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "targetAuthorizationEpochs", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "targetOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "usedCommitments", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "name": "validatorSetDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "name": "validatorThresholds", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "validatorVoted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "validators", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "verdictVotes", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "programId", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + } + ], + "name": "withdrawProgramFunds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "60e0604052346103f257613c4b8038038061001981610425565b92833981019060a0818303126103f2576100328161044a565b61003e6020830161044a565b60408301516001600160401b0381116103f25783019184601f840112156103f2578251946001600160401b03861161040f578560051b936020610082818701610425565b809881520190602082968201019283116103f257602001905b8282106103f75750505060608401519360ff85168095036103f25760800151906001600160401b038216908183036103f25760018080556002556001600160a01b0381169182159182156103e8575b5081156103d6575b81156103cc575b81156103c0575b81156103b3575b506103825760805260a0528060c0528351600281109081156103a8575b811561039d575b8115610393575b50610382576000549163ffffffff8360081c1663ffffffff811461036c576001019264ffffffff0063ffffffff85169460081b169064ffffffff0019161760005582600052600460205260406000208460ff1982541617905560005b855181101561022957600581901b8601602001516000906001600160a01b0316801580156101ff575b6101f0578582526003602090815260408084206001600160a01b0390931684529190529020805460ff191660019081179091550161018e565b63b4fa3fb360e01b8252600482fd5b508582526003602090815260408084206001600160a01b038416855290915282205460ff166101b7565b508491936040519260408401918452604060208501525180915260608301919060005b81811061034d5750505090807fa8e46202f74d95810010d9b0eba20a8a965a8391285ce9ee6e87eb41c052e346920390a2604051906001600160a01b03167fe26019fd01a41dc1acbe59fa90d0a634eb009e4d8a1398dedc8b1c98a9ff1569600080a26137ec908161045f823960805181818161245601528181612f56015281816133d10152613683015260a0518181816118990152818161199201528181611bb101528181611c450152818161230f0152612aab015260c05181818161022c0152818161033201528181610c9101528181610fdb015281816115f8015281816120af0152818161237b015281816126bf0152818161277701526128290152f35b82516001600160a01b031684526020938401939092019160010161024c565b634e487b7160e01b600052601160045260246000fd5b63b4fa3fb360e01b60005260046000fd5b9050831138610132565b60028510915061012b565b602081119150610124565b62278d0091501138610107565b610e1081109150610100565b843b1591506100f9565b6001600160a01b0385161591506100f2565b3b159150386100ea565b600080fd5b602080916104048461044a565b81520191019061009b565b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b0381118382101761040f57604052565b51906001600160a01b03821682036103f25756fe6080604052600436101561001257600080fd5b60003560e01c806309033c0d146127a65780630c340a24146127615780630e54ceea1461272957806316c38b3c1461269f5780632612b26b14612513578063290534ef146124c15780632ed70b34146124855780633013ce29146124405780633567bfd61461240a5780633582410d1461235157806335b96901146123335780634168df97146122ef5780634e4604a31461204a57806350d8da2c14611f6d578063543c406514611f33578063580f201e14611f0c578063595b557314611dc35780635c975abb14611da05780635ecdd9e114611cc75780637270b5f5146117085780637276d8bc146116d357806375ddb5fc146115e2578063872572e0146115b6578063907d90231461133d57806392db281614611296578063933b80281461125c5780639da92fe41461122b578063a3368a8a146111e8578063ad73349e146110b8578063ae169a5014611085578063af76a49e14610fc0578063b2daf93014610f8c578063b3b1655614610e2e578063ba4556eb14610de1578063ba71b33014610dc3578063c9d7c65914610d8e578063cc601c0214610c72578063d5884f3314610b88578063dbff93e514610762578063dc9ebd571461072c578063ed556de5146106d3578063f6618ac41461054d578063f8541b7a14610505578063fa5202b11461031c578063fa72a0eb146102e05763fff7f72b1461021657600080fd5b346102db5760203660031901126102db576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5780600052600e6020526001600160401b0360406000205416156102ba5780600052600e60205260406000206001600160401b031981541690557f7467ebb03e153f9c1b33c936116e0c8ef06b2f7329b8ea0308ed5e516ab2bfa2600080a2005b63baf3f0f760e01b60005260046000fd5b6282b42960e81b60005260046000fd5b600080fd5b346102db5760803660031901126102db5760243580151581036102db576044359060048210156102db5761031a9160643591600435612b53565b005b346102db5760203660031901126102db576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5780600052600a6020526040600020600a810160ff815460601c161580156104fc575b80156104e4575b80156104b1575b6102ba5760038201549081600052600760205260018060a01b03604060002054169160005260086020526001600160401b036040600020541682600052600660205260406000205490831580156104a9575b610498576002850180546001600160a01b038681166001600160a01b031983161790925584546001600160401b03841667ffffffffffffffff1990911617909455600686019290925560405190815291169084907fea9e62b427a537eaed6a849922fc203023efd7b350e6e28365a736e44e97f28690602090a460ff600882015460081c1660068110156104825760041461047957005b61031a916135e8565b634e487b7160e01b600052602160045260246000fd5b63b4fa3fb360e01b60005260046000fd5b5081156103e2565b5060ff600883015460081c16600681101561048257600381141590816104d8575b50610390565b600491501415846104d2565b5082600052601160205260ff60406000205416610389565b50815415610382565b346102db5760403660031901126102db5761051e6128bd565b600435600052601060205260406000209060018060a01b03166000526020526020604060002054604051908152f35b346102db5760403660031901126102db576004356024356001600160401b0381116102db57366023820112156102db5780600401356001600160401b0381116102db57602482019160248236920101116102db5782600052600a602052604060002060ff600a82015460601c161580156106a4575b6102cb5781156104985761080082116106935760018101546001600160a01b031633810361068b5750600201546001600160a01b0316925b7fd2450303494e0173137ecff8f741ada0d1b42c811df9898b72238edd1928855e61062483612b00565b94610632604051968761293f565b838652836020870160009782888337886020848301015251902095604051968752604060208801528160408801526060870137856060858701015260018060a01b0316936060813395601f80199101168101030190a480f35b9050926105fa565b636ceaf82160e01b60005260046000fd5b5060018101546001600160a01b031633148015906105c2575060028101546001600160a01b03163314156105c2565b346102db5760403660031901126102db576106ec612894565b63ffffffff6106f96128bd565b9116600052600360205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b346102db5760803660031901126102db57602061075a61074a6128bd565b6064359060443590600435612a55565b604051908152f35b346102db5760a03660031901126102db5761077b6128a7565b608435906001600160401b03821682036102db5760ff60005416610b77576001600160a01b038116158015610b65575b8015610b5b575b61049857610e104201804211610b45576001600160401b038316108015610b27575b610498576000604435158015610b1d575b8015610b0a575b8015610aea575b610adb57506002549061080582612a39565b60025560018060a01b03811660005260066020526040600020549263ffffffff60005460081c16604051946108398661290d565b6000865233602087015260018060a01b03841660408701526024356060870152604435608087015260643560a087015260c0860152600060e086015260006101008601526000610120860152600061014086015260006101608601526001600160401b0342166101808601526101a085016001600160401b03831681526101c0860191600083526101e087019081526102008701916001835286600052600a60205260406000208851815560018060a01b0360208a015116600182019060018060a01b03166001600160601b0360a01b82541617905560018060a01b0360408a015116600282019060018060a01b03166001600160601b0360a01b825416179055606089015160038201556080890151600482015560a0890151600582015560c0890151600682015560e08901516007820155600881016101008a01516004811015610482576109899082612b3b565b6101208a01519160068310156104825760209a6001600160401b03946109cb846109b68897600a976129bb565b6001600160801b03610140850151169061310e565b61018060098401926001600160801b038061016083015116166001600160801b03198554161784550151906001600160801b038354918760c01b905160c01b16928760801b9060801b1691161717905501945116166001600160401b0319845416178355519063ffffffff60401b83549160ff60601b9051151560601b169260401b169064ffffffffff60401b1916171790556001600160401b0363ffffffff60005460081c16916040519360018060a01b03168452602435868501526044356040850152606435606085015216608083015260a0820152600060c08201526000827f08a7e7ee077b43ee75408d116f37fb84c47e1cfe7e91265457013512039d6c0060e03394a4604051908152f35b63b4fa3fb360e01b8152600490fd5b5063ffffffff815460081c168152600560205260ff6040822054166107f3565b50426001600160401b03841611156107ec565b50606435156107e5565b5062278d004201804211610b45576001600160401b038316116107d4565b634e487b7160e01b600052601160045260246000fd5b50602435156107b2565b506001600160a01b03811633146107ab565b6313d0ff5960e31b60005260046000fd5b346102db57610b963661286e565b6001601254146102ba576001601255600082815260096020526040902080546001600160a01b031633036102cb5760030190815460ff8160401c168015610c61575b8015610c43575b6102ba576001600160801b0392610bfe8385610c049460681c166128e0565b90612980565b1690610c1082336133ba565b6040519182527f2c84e63caeee238c9901749ad657a1e19b035524c1cb057447fe532249bd640160203393a36000601255005b506001600160801b038160681c166001600160801b03831611610bdf565b506001600160801b03821615610bd8565b346102db5760403660031901126102db57600435610c8e6128bd565b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5780158015610d7d575b610498576000818152600760205260409020546001600160a01b03928316921682146102ba578060005260086020527f38f54530a874b20fd349e150f62a1ad6a2a3f82ac187a5f352775f0173f41da160206040600020610d326001600160401b038254166129da565b906001600160401b0382166001600160401b031982541617905583600052600782526040600020856001600160601b0360a01b8254161790556001600160401b0360405191168152a3005b506001600160a01b03821615610cc8565b346102db5760203660031901126102db57600435600052600e60205260206001600160401b0360406000205416604051908152f35b346102db5760003660031901126102db576020600154604051908152f35b346102db5760403660031901126102db57610dfa6128bd565b600435600052600b60205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b346102db5760203660031901126102db576004356001601254146102ba57600160125580600052600a602052604060002060ff600a82015460601c16158015610f82575b6102ba5760ff600882015460081c1690600682101590816104825760028314159081610f72575b81610f61575b506102ba576104825760038114908115610f56575b506102ba5760008181526010602090815260408083203384529091529020549081156102ba57806000526010602052604060002060018060a01b0333166000526020526000604081205580600052600f6020526040600020610f17838254612a48565b9055610f2382336133ba565b6040519182527f3dfd70209502a0910e39981b95e37a3e29b534a556fe51f0e1c65c191535351760203393a36000601255005b600491501482610eb4565b60099150015460c01c421084610e9f565b6000925060058414159150610e99565b5080541515610e72565b346102db5760203660031901126102db576004356000526007602052602060018060a01b0360406000205416604051908152f35b346102db5760203660031901126102db57610fd9612894565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5763ffffffff1680600052600460205260ff6040600020541615801561106d575b6102ba578060005260056020526040600020600160ff198254161790557fe0ab397a66eea64954658eb017b55dfcd79ab46062005a22dbd2cd982636557b600080a2005b5080600052600560205260ff60406000205416611029565b346102db5760203660031901126102db576001601254146102ba5760016012556110b13360043561323c565b6000601255005b346102db5760203660031901126102db57600435600052600a6020526040600020805460018060a01b036001830154169160018060a01b03600282015416926003820154916004810154600582015460068301549060078401549260088501549660ff8860081c1699600a6009880154970154976040519a8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152611166610100850160ff85166128d3565b6006851015610482576001600160801b0360ff936102209661012087015260101c166101408501526001600160801b0381166101608501526001600160401b038160801c1661018085015260c01c6101a08401526001600160401b0381166101c084015263ffffffff8160401c166101e084015260601c161515610200820152f35b346102db5760403660031901126102db576112016128bd565b6001601254146102ba5760016012556001600160a01b03811615610498576110b19060043561323c565b346102db5760203660031901126102db576004356000526011602052602060ff604060002054166040519015158152f35b346102db5760203660031901126102db5763ffffffff61127a612894565b166000526004602052602060ff60406000205416604051908152f35b346102db5760203660031901126102db576004356000526009602052610120604060002060018060a01b03815416906001600160801b03600182015491600281015482600460038401549301541693604051958652602086015260408501526001600160401b038116606085015260ff8160401c161515608085015261ffff8160481c1660a085015261ffff8160581c1660c085015260681c1660e0830152610100820152f35b346102db5760e03660031901126102db576004356024353660c4116102db5760c4359161ffff8316918284036102db57811580156115ae575b801561158e575b8015611586575b801561157c575b6104985733600052600660205260406000205415610498576001600160801b036113b36129f7565b16158015611559575b8015611536575b8015611508575b61049857600154926113db84612a39565b6001908155600085815260096020908152604080832080546001600160a01b031916331781559384018790556002840186905586835260089091528120546003830180546cffff0000ffffffffffffffffff19166001600160401b03929092169190911760589890981b61ffff60581b16979097176801000000000000000017909655946044905b600281106114aa5750506020945060405191825284820152827f15fad9d1771e99cbbfd09e28642148ef9a495280448869c5a90ec8bae1e1ff0360403393a4604051908152f35b6000805b600281106114c6575087820160050155600101611463565b929060009082356001600160801b03811692838203611505575091602091600193506001600160801b038760071b92831b921b191617920193016114ae565b80fd5b5060a4356001600160801b038116908181036102db57506001600160801b0361152f612a23565b16116113ca565b5061153f612a23565b6001600160801b0380611550612a0d565b169116106113c3565b50611562612a0d565b6001600160801b03806115736129f7565b169116106113bc565b506040831161138b565b508215611384565b5081600052600760205260018060a01b036040600020541633141561137d565b508015611376565b346102db5760203660031901126102db57600435600052600f6020526020604060002054604051908152f35b346102db5760203660031901126102db576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb576000818152600760205260409020546001600160a01b03169081156102ba5780600052600760205260406000206001600160601b0360a01b81541690558060005260086020527f91efe0fbddf615be187704e41356d1a0c8b7c934c5fcabd77c71dadb32f00358602060406000206116a76001600160401b038254166129da565b906001600160401b0382166001600160401b03198254161790556001600160401b0360405191168152a3005b346102db5760203660031901126102db57600435600052600860205260206001600160401b0360406000205416604051908152f35b346102db5760603660031901126102db5760ff60005416610b77576004356000526009602052604060002060038101805460ff8160401c1615908115611cb5575b8115611c9d575b506102ba57600435600052600d602052604060002060443560005260205260ff60406000205416611c8c5761178d60443560243533600435612a55565b80600052600e6020526001600160401b03604060002054164210156102cb57600052600e60205260406000206001600160401b03198154169055600435600052600d60205260406000206044356000526020526040600020600160ff19825416179055600682015460801c916001600160801b03825460681c16838110611c7b5761181b84611821926128e0565b83612980565b600481016001600160801b0361183a8582845416612960565b166001600160801b031982541617905561ffff825460481c1661ffff8114610b455782546affff000000000000000000191660019190910160481b61ffff60481b161782556001808060a01b03825416910154916001600160401b03807f0000000000000000000000000000000000000000000000000000000000000000168142160111610b4557546001600160401b03166000602435158015611c71575b8015611c38575b8015611c18575b610adb5750600254926118f984612a39565b6002558260005260066020526040600020549463ffffffff60005460081c1690604051966119268861290d565b6004358852336020890152856040890152836060890152602435608089015260443560a089015260c0880152600060e08801526000610100880152600061012088015261014087015260006101608701526001600160401b0342166101808701526001600160401b03807f00000000000000000000000000000000000000000000000000000000000000001681421601166101a0870152826101c08701526101e0860152600161020086015283600052600a6020526040600020948051865560018060a01b03602082015116600187019060018060a01b03166001600160601b0360a01b82541617905560018060a01b03604082015116600287019060018060a01b03166001600160601b0360a01b825416179055606081015160038701556080810151600487015560a0810151600587015560c0810151600687015560e08101516007870155610100810151600481101561048257611a899060088801612b3b565b61012081015160068110156104825786611aaa600a92600860209a016129bb565b611ac56001600160801b03610140850151166008830161310e565b600981016001600160801b038061016086015116166001600160801b031982541617815561018084015181546001600160801b036001600160401b0360c01b6101a088015160c01b16926001600160401b0360801b9060801b1691161717905501906001600160401b03806101c083015116166001600160401b03198354161782556101e08101519063ffffffff60401b83549161020060ff60601b910151151560601b169260401b169064ffffffffff60401b19161717905563ffffffff60005460081c169060405193845285840152602435604084015260443560608401526001600160401b03807f0000000000000000000000000000000000000000000000000000000000000000168142160116608084015260a083015260c08201523390827f08a7e7ee077b43ee75408d116f37fb84c47e1cfe7e91265457013512039d6c0060e060043593a4604051908152f35b5063ffffffff815460081c168152600560205260ff6040822054166118e7565b50426001600160401b03807f000000000000000000000000000000000000000000000000000000000000000016814216011611156118e0565b50604435156118d9565b631217157160e31b60005260046000fd5b63721d2c7d60e11b60005260046000fd5b905061ffff808260581c169160481c16101583611750565b9050611cc0836130b9565b1590611749565b346102db5760203660031901126102db5760043580600052600a602052604060002060ff600a82015460601c16158015611d90575b8015611d5f575b6102ba5760088101805461ff0019166105001790558054611d47575b507fbfec5f0aff1e5c47b5f8ec8afdb3fed880f753daf622e718a9b7c385cf416ddd600080a2005b80611d54611d5992613132565b6131ed565b81611d1f565b5060ff600882015460081c166006811015610482578015159081611d84575b50611d03565b60019150141583611d7e565b50600981015460c01c4210611cfc565b346102db5760003660031901126102db57602060ff600054166040519015158152f35b346102db5760203660031901126102db5760043580600052600a60205260406000209060ff600a83015460601c16158015611f02575b8015611eeb575b6102cb576008820160ff815460081c16600681101561048257600114801590611eda575b6102ba5781600052600f6020526040600020549283158015611eca575b611c7b573360005260066020526040600020549081156104985760068101919091556009810180546001600160801b0319166001600160801b038616179055815461ff00191661030017909155600101546040519283526001600160a01b0316917f9f5a10e8d25c68b39aad7500064a8ac8a8458431267fc74cfea14a320bc8cf2290602090a3005b506001600160801b038411611e41565b50600983015460c01c421015611e24565b5060028201546001600160a01b0316331415611e00565b5081541515611df9565b346102db5760003660031901126102db57602063ffffffff60005460081c16604051908152f35b346102db5760203660031901126102db576001600160a01b03611f546128a7565b1660005260066020526020604060002054604051908152f35b346102db57611f7b3661286e565b9060ff60005416610b77576001601254146102ba5760016012558060005260096020526040600020600381019060ff825460401c1615908115612038575b8115612027575b506102ba57611ff490610bfe6001600160801b03851694611fe18633612f41565b6001600160801b03835460681c16612960565b6040519182527f995fe54ed2f5efe5acfcee883c9f3cdff46788cd0d14871c15f69eea22015d1a60203393a36000601255005b61203191506130b9565b1584611fc0565b6001600160801b038516159150611fb9565b346102db5760403660031901126102db576004356001600160401b0381116102db57366023820112156102db578060040135906001600160401b0382116102db578160051b90602482820101913683116102db576024359260ff84168094036102db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb576000946120f0602060405194018461293f565b8252602082019260240190835b8183106122cb575050508051600281109081156122c0575b81156122b5575b81156122ab575b5061229c5783549163ffffffff8360081c1663ffffffff8114612288576001019264ffffffff0063ffffffff85169460081b169064ffffffff0019161785558285526004602052604085208460ff19825416179055845b825181101561221257600581901b8301602001516001600160a01b0316801580156121e8575b6121d9578487526003602090815260408089206001600160a01b0390931689529190528620805460ff191660019081179091550161217a565b63b4fa3fb360e01b8752600487fd5b508487526003602090815260408089206001600160a01b0384168a5290915287205460ff166121a0565b50604080519485526020850181905291519184018290526060840191855b81811061226957602085807fa8e46202f74d95810010d9b0eba20a8a965a8391285ce9ee6e87eb41c052e3468988038aa2604051908152f35b82516001600160a01b0316845260209384019390920191600101612230565b634e487b7160e01b86526011600452602486fd5b63b4fa3fb360e01b8452600484fd5b9050831185612123565b60028510915061211c565b602081119150612115565b82356001600160a01b03811681036122eb578152602092830192016120fd565b8780fd5b346102db5760003660031901126102db5760206040516001600160401b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102db5760003660031901126102db576020600254604051908152f35b346102db5760403660031901126102db576004356024356001600160401b0381168091036102db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5781158015612400575b6104985760207fe06ae3bcd9084813a82ea66e6eacec3e8e03ec3d26e4e2c6a803f840cd593fd29183600052600e82526040600020816001600160401b0319825416179055604051908152a2005b50428111156123b2565b346102db5761241836612858565b90600052600c602052604060002090600052602052602060ff60406000205416604051908152f35b346102db5760003660031901126102db576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346102db5760203660031901126102db5763ffffffff6124a3612894565b166000526005602052602060ff604060002054166040519015158152f35b346102db5760203660031901126102db5760043580156104985733600052600660205280604060002055337f8d8b69f1bb77e4fa4a4dbf1148de1d1b3b3cc9255e919acc37a53ead6b40212f600080a3005b346102db576125213661286e565b9060ff60005416610b77576001601254146102ba57600160125580600052600a602052604060002060ff600a82015460601c1615908115612694575b8115612682575b8115612670575b811561263e575b506102ba5780600052600f6020526001600160801b03604060002054921691826001600160801b03036001600160801b038111610b45576001600160801b031610611c7b576125c18233612f41565b80600052600f60205260406000206125da838254612900565b9055806000526010602052604060002060018060a01b0333166000526020526040600020612609838254612900565b90556040519182527f08db86f4e1cb0e2198df440c670725321f5a649819c04754acdb565dcc90c59160203393a36000601255005b60ff91506008015460081c166006811015610482578015159081612664575b5083612572565b6001915014158361265d565b600981015460c01c421015915061256b565b6001600160801b038416159150612564565b80541515915061255d565b346102db5760203660031901126102db576004358015158091036102db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5760207f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec59160ff196000541660ff821617600055604051908152a1005b346102db5761273736612858565b90600052600d602052604060002090600052602052602060ff604060002054166040519015158152f35b346102db5760003660031901126102db576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346102db5760203660031901126102db57600435806000526009602052604060002060018060a01b0381541633141580612825575b6102cb57600301805460ff8160401c16156102ba5768ff0000000000000000191690557f084b873cdb285c0ffe7c178ff857b1c69935dd322c91a660c7ac8bda800dcef5600080a2005b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614156127db565b60409060031901126102db576004359060243590565b60409060031901126102db57600435906024356001600160801b03811681036102db5790565b6004359063ffffffff821682036102db57565b600435906001600160a01b03821682036102db57565b602435906001600160a01b03821682036102db57565b9060048210156104825752565b906001600160801b03809116911603906001600160801b038211610b4557565b91908201809211610b4557565b61022081019081106001600160401b0382111761292957604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b0382111761292957604052565b906001600160801b03809116911601906001600160801b038211610b4557565b80546fffffffffffffffffffffffffffffffff60681b191660689290921b6fffffffffffffffffffffffffffffffff60681b16919091179055565b9060068110156104825761ff0082549160081b169061ff001916179055565b6001600160401b03166001600160401b038114610b455760010190565b6044356001600160801b03811681036102db5790565b6064356001600160801b03811681036102db5790565b6084356001600160801b03811681036102db5790565b6000198114610b455760010190565b91908203918211610b4557565b9290918360005260096020526001600160401b03600360406000200154169263ffffffff60005460081c166040519460208601964688523060408801526060870152608086015260a08501526001600160401b037f00000000000000000000000000000000000000000000000000000000000000001660c085015260018060a01b031660e08401526101008301526101208201526101208152612afa6101408261293f565b51902090565b6001600160401b03811161292957601f01601f191660200190565b612b3760409295949360608301961515835260208301906128d3565b0152565b9060048110156104825760ff80198354169116179055565b90929181600052600a602052604060002092600a8401805460ff8160601c1615908115612f23575b8115612f11575b8115612f08575b8115612ee5575b8115612eb8575b506102ba576000848152600b6020908152604080832033845290915290205460ff16612ea75784548015159081612e89575b506102cb576000848152600b60209081526040808320338452825291829020805460ff19166001179055905190810190612c1781612c0986888c87612b1b565b03601f19810183528261293f565b51902084600052600c60205260406000208160005260205260406000209160ff8354169160ff8314610b4557600163ffffffff93019360ff851660ff1982541617905588877fc08b572a950997b2bb69414b8dc0a0243c10ebef137da8d462434bf43907e6ad60405180612c8e8a8c339784612b1b565b0390a45460401c16600052600460205260ff8060406000205416911610612e82578060078501556008840194612cc48387612b3b565b15612e3857604083927f772550e90dca710b0fb450a3e13e2b8b17875e5af5831335797158212fb6c08b9261010061ff0019895416178855612d08835180936128d3565b6020820152a2815480612d1c575b50505050565b6000526009602052604060002090835493600460ff8616101561048257612dbb6001600160801b0393610bfe6003612d7c612e2f99886005607f8360011c168701016080610ff08460041b16915491861b161c1698899160101c166128e0565b92600481016001600160801b03612d9686828454166128e0565b166001600160801b031982541617905501916001600160801b03835460681c16612960565b612dc5838261310e565b6009840180546001600160801b0319166001600160801b038516179055805461ff00191661030017905560018301546040519283526001600160a01b0316917f9f5a10e8d25c68b39aad7500064a8ac8a8458431267fc74cfea14a320bc8cf2290602090a36131ed565b38808080612d16565b9050612e797f2cfe88a88188abcf3e8147252014fcafae5e64035cc180a0c8fab2072ac46462936020939561020061ff0019825416179055611d5481613132565b604051908152a2565b5050505050565b90506000526009602052612ea060406000206130b9565b1538612bc9565b6303af45a960e21b60005260046000fd5b604090811c63ffffffff166000908152600360209081528282203383529052205460ff1615905038612b97565b905063ffffffff8160401c16600052600560205260ff6040600020541690612b90565b83159150612b89565b600987015460c01c4210159150612b82565b905060ff600887015460081c16600681101561048257151590612b7b565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316939291602082602481885afa91821561307857600092613084575b5060249394612fe0602092604051906323b872dd60e01b8583015260018060a01b03168782015230604482015285606482015260648152612fdb60848261293f565b613675565b6040516370a0823160e01b815230600482015294859182905afa92831561307857600093613044575b5080831092831561302f575b50505061301e57565b6312171d8360e31b60005260046000fd5b61303a929350612a48565b1415388080613015565b90926020823d602011613070575b8161305f6020938361293f565b810103126115055750519138613009565b3d9150613052565b6040513d6000823e3d90fd5b90916020823d6020116130b1575b8161309f6020938361293f565b81010312611505575051906024612f99565b3d9150613092565b600181015460008181526007602052604090205482546001600160a01b039081169116149190826130e957505090565b90915060005260086020526001600160401b0360038160406000205416920154161490565b9062010000600160901b0382549160101b169062010000600160901b031916179055565b8054801580156131d5575b6131d15760005260096020526131b6600860406000209201916001600160801b03835460101c166001600160801b0361317d6004840192828454166128e0565b166001600160801b0319825416179055610bfe60036001600160801b03855460101c169201916001600160801b03835460681c16612960565b805471ffffffffffffffffffffffffffffffff000019169055565b5050565b506001600160801b03600883015460101c161561313d565b548015613239576000526009602052600360406000200161ffff815460481c169081156102ba57613237916000190161ffff60481b82549160481b169061ffff60481b1916179055565b565b50565b9081600052600a60205260406000209060ff600a83015460601c161580156133a3575b8015613385575b8015613370575b6102ba576001600160801b03600983015416906008830161040061ff00198254161790558254151560001461335b578254600052600960205260046040600020016001600160801b036132c384828454166128e0565b166001600160801b03198254161790555b6132de82826133ba565b6040519182526001600160a01b031690339084907f56a43be815d86b39dc4d398124c956790410b5e9cf70d477de0299f25fc1831390602090a461332181613751565b1561332f57613237916135e8565b60030154907ff3c0e221c17643f4f2d5f37d5aa7fed18c5ee55c2860680d80799babc7c075ec600080a3565b83600052600f602052600060408120556132d4565b506001600160801b036009830154161561326d565b5060ff600883015460081c1660068110156104825760031415613266565b5060018201546001600160a01b031633141561325f565b6040516370a0823160e01b815230600482015291907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602084602481845afa938415613078576000946135b4575b506040516370a0823160e01b81526001600160a01b0390921660048301819052602083602481855afa92831561307857600093613580575b5061347860405163a9059cbb60e01b602082015282602482015285604482015260448152612fdb60648261293f565b6040516370a0823160e01b815230600482015290602082602481865afa9182156130785760009261354b575b506020906024604051809581936370a0823160e01b835260048301525afa91821561307857600092613517575b508481119485156134ff575b505083156134f5575b831561302f5750505061301e57565b81811093506134e6565b849295509061350d91612a48565b14159238806134dd565b90916020823d602011613543575b816135326020938361293f565b8101031261150557505190386134d1565b3d9150613525565b90916020823d602011613578575b816135666020938361293f565b810103126115055750519060206134a4565b3d9150613559565b90926020823d6020116135ac575b8161359b6020938361293f565b810103126115055750519138613449565b3d915061358e565b90936020823d6020116135e0575b816135cf6020938361293f565b810103126115055750519238613411565b3d91506135c2565b80600052601160205260ff604060002054166102ba576002820180546001600160a01b0316600090815260066020526040902054928315610498576006018390556000828152601160205260408120805460ff1916600117905590546001600160a01b031691907f8602905161aae8f4629b90f661645ab49c43e18661ab6b353be8ce8f81c9fed99080a4565b8051600091829190602001827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af13d15613749573d906136be82612b00565b916136cc604051938461293f565b82523d6000602084013e5b15908115613728575b81156136ee575b5061301e57565b805160208114925082613704575b5050386136e7565b81925090602091810103126102db57602001518015908115036102db5738806136fc565b80915051801515908161373d575b50906136e0565b60209150141538613736565b6060906136d7565b8054156137b057600381015460008181526007602052604090205460028301546001600160a01b0390811691161491908261378b57505090565b90915060005260086020526001600160401b03600a8160406000205416920154161490565b5060019056fea26469706673582212208806b5f4670884dc0279ac0fecca1ece742bb4cb46c701e73e4b2c5651811d7564736f6c63430008210033", + "runtime_template": "6080604052600436101561001257600080fd5b60003560e01c806309033c0d146127a65780630c340a24146127615780630e54ceea1461272957806316c38b3c1461269f5780632612b26b14612513578063290534ef146124c15780632ed70b34146124855780633013ce29146124405780633567bfd61461240a5780633582410d1461235157806335b96901146123335780634168df97146122ef5780634e4604a31461204a57806350d8da2c14611f6d578063543c406514611f33578063580f201e14611f0c578063595b557314611dc35780635c975abb14611da05780635ecdd9e114611cc75780637270b5f5146117085780637276d8bc146116d357806375ddb5fc146115e2578063872572e0146115b6578063907d90231461133d57806392db281614611296578063933b80281461125c5780639da92fe41461122b578063a3368a8a146111e8578063ad73349e146110b8578063ae169a5014611085578063af76a49e14610fc0578063b2daf93014610f8c578063b3b1655614610e2e578063ba4556eb14610de1578063ba71b33014610dc3578063c9d7c65914610d8e578063cc601c0214610c72578063d5884f3314610b88578063dbff93e514610762578063dc9ebd571461072c578063ed556de5146106d3578063f6618ac41461054d578063f8541b7a14610505578063fa5202b11461031c578063fa72a0eb146102e05763fff7f72b1461021657600080fd5b346102db5760203660031901126102db576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5780600052600e6020526001600160401b0360406000205416156102ba5780600052600e60205260406000206001600160401b031981541690557f7467ebb03e153f9c1b33c936116e0c8ef06b2f7329b8ea0308ed5e516ab2bfa2600080a2005b63baf3f0f760e01b60005260046000fd5b6282b42960e81b60005260046000fd5b600080fd5b346102db5760803660031901126102db5760243580151581036102db576044359060048210156102db5761031a9160643591600435612b53565b005b346102db5760203660031901126102db576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5780600052600a6020526040600020600a810160ff815460601c161580156104fc575b80156104e4575b80156104b1575b6102ba5760038201549081600052600760205260018060a01b03604060002054169160005260086020526001600160401b036040600020541682600052600660205260406000205490831580156104a9575b610498576002850180546001600160a01b038681166001600160a01b031983161790925584546001600160401b03841667ffffffffffffffff1990911617909455600686019290925560405190815291169084907fea9e62b427a537eaed6a849922fc203023efd7b350e6e28365a736e44e97f28690602090a460ff600882015460081c1660068110156104825760041461047957005b61031a916135e8565b634e487b7160e01b600052602160045260246000fd5b63b4fa3fb360e01b60005260046000fd5b5081156103e2565b5060ff600883015460081c16600681101561048257600381141590816104d8575b50610390565b600491501415846104d2565b5082600052601160205260ff60406000205416610389565b50815415610382565b346102db5760403660031901126102db5761051e6128bd565b600435600052601060205260406000209060018060a01b03166000526020526020604060002054604051908152f35b346102db5760403660031901126102db576004356024356001600160401b0381116102db57366023820112156102db5780600401356001600160401b0381116102db57602482019160248236920101116102db5782600052600a602052604060002060ff600a82015460601c161580156106a4575b6102cb5781156104985761080082116106935760018101546001600160a01b031633810361068b5750600201546001600160a01b0316925b7fd2450303494e0173137ecff8f741ada0d1b42c811df9898b72238edd1928855e61062483612b00565b94610632604051968761293f565b838652836020870160009782888337886020848301015251902095604051968752604060208801528160408801526060870137856060858701015260018060a01b0316936060813395601f80199101168101030190a480f35b9050926105fa565b636ceaf82160e01b60005260046000fd5b5060018101546001600160a01b031633148015906105c2575060028101546001600160a01b03163314156105c2565b346102db5760403660031901126102db576106ec612894565b63ffffffff6106f96128bd565b9116600052600360205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b346102db5760803660031901126102db57602061075a61074a6128bd565b6064359060443590600435612a55565b604051908152f35b346102db5760a03660031901126102db5761077b6128a7565b608435906001600160401b03821682036102db5760ff60005416610b77576001600160a01b038116158015610b65575b8015610b5b575b61049857610e104201804211610b45576001600160401b038316108015610b27575b610498576000604435158015610b1d575b8015610b0a575b8015610aea575b610adb57506002549061080582612a39565b60025560018060a01b03811660005260066020526040600020549263ffffffff60005460081c16604051946108398661290d565b6000865233602087015260018060a01b03841660408701526024356060870152604435608087015260643560a087015260c0860152600060e086015260006101008601526000610120860152600061014086015260006101608601526001600160401b0342166101808601526101a085016001600160401b03831681526101c0860191600083526101e087019081526102008701916001835286600052600a60205260406000208851815560018060a01b0360208a015116600182019060018060a01b03166001600160601b0360a01b82541617905560018060a01b0360408a015116600282019060018060a01b03166001600160601b0360a01b825416179055606089015160038201556080890151600482015560a0890151600582015560c0890151600682015560e08901516007820155600881016101008a01516004811015610482576109899082612b3b565b6101208a01519160068310156104825760209a6001600160401b03946109cb846109b68897600a976129bb565b6001600160801b03610140850151169061310e565b61018060098401926001600160801b038061016083015116166001600160801b03198554161784550151906001600160801b038354918760c01b905160c01b16928760801b9060801b1691161717905501945116166001600160401b0319845416178355519063ffffffff60401b83549160ff60601b9051151560601b169260401b169064ffffffffff60401b1916171790556001600160401b0363ffffffff60005460081c16916040519360018060a01b03168452602435868501526044356040850152606435606085015216608083015260a0820152600060c08201526000827f08a7e7ee077b43ee75408d116f37fb84c47e1cfe7e91265457013512039d6c0060e03394a4604051908152f35b63b4fa3fb360e01b8152600490fd5b5063ffffffff815460081c168152600560205260ff6040822054166107f3565b50426001600160401b03841611156107ec565b50606435156107e5565b5062278d004201804211610b45576001600160401b038316116107d4565b634e487b7160e01b600052601160045260246000fd5b50602435156107b2565b506001600160a01b03811633146107ab565b6313d0ff5960e31b60005260046000fd5b346102db57610b963661286e565b6001601254146102ba576001601255600082815260096020526040902080546001600160a01b031633036102cb5760030190815460ff8160401c168015610c61575b8015610c43575b6102ba576001600160801b0392610bfe8385610c049460681c166128e0565b90612980565b1690610c1082336133ba565b6040519182527f2c84e63caeee238c9901749ad657a1e19b035524c1cb057447fe532249bd640160203393a36000601255005b506001600160801b038160681c166001600160801b03831611610bdf565b506001600160801b03821615610bd8565b346102db5760403660031901126102db57600435610c8e6128bd565b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5780158015610d7d575b610498576000818152600760205260409020546001600160a01b03928316921682146102ba578060005260086020527f38f54530a874b20fd349e150f62a1ad6a2a3f82ac187a5f352775f0173f41da160206040600020610d326001600160401b038254166129da565b906001600160401b0382166001600160401b031982541617905583600052600782526040600020856001600160601b0360a01b8254161790556001600160401b0360405191168152a3005b506001600160a01b03821615610cc8565b346102db5760203660031901126102db57600435600052600e60205260206001600160401b0360406000205416604051908152f35b346102db5760003660031901126102db576020600154604051908152f35b346102db5760403660031901126102db57610dfa6128bd565b600435600052600b60205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b346102db5760203660031901126102db576004356001601254146102ba57600160125580600052600a602052604060002060ff600a82015460601c16158015610f82575b6102ba5760ff600882015460081c1690600682101590816104825760028314159081610f72575b81610f61575b506102ba576104825760038114908115610f56575b506102ba5760008181526010602090815260408083203384529091529020549081156102ba57806000526010602052604060002060018060a01b0333166000526020526000604081205580600052600f6020526040600020610f17838254612a48565b9055610f2382336133ba565b6040519182527f3dfd70209502a0910e39981b95e37a3e29b534a556fe51f0e1c65c191535351760203393a36000601255005b600491501482610eb4565b60099150015460c01c421084610e9f565b6000925060058414159150610e99565b5080541515610e72565b346102db5760203660031901126102db576004356000526007602052602060018060a01b0360406000205416604051908152f35b346102db5760203660031901126102db57610fd9612894565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5763ffffffff1680600052600460205260ff6040600020541615801561106d575b6102ba578060005260056020526040600020600160ff198254161790557fe0ab397a66eea64954658eb017b55dfcd79ab46062005a22dbd2cd982636557b600080a2005b5080600052600560205260ff60406000205416611029565b346102db5760203660031901126102db576001601254146102ba5760016012556110b13360043561323c565b6000601255005b346102db5760203660031901126102db57600435600052600a6020526040600020805460018060a01b036001830154169160018060a01b03600282015416926003820154916004810154600582015460068301549060078401549260088501549660ff8860081c1699600a6009880154970154976040519a8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152611166610100850160ff85166128d3565b6006851015610482576001600160801b0360ff936102209661012087015260101c166101408501526001600160801b0381166101608501526001600160401b038160801c1661018085015260c01c6101a08401526001600160401b0381166101c084015263ffffffff8160401c166101e084015260601c161515610200820152f35b346102db5760403660031901126102db576112016128bd565b6001601254146102ba5760016012556001600160a01b03811615610498576110b19060043561323c565b346102db5760203660031901126102db576004356000526011602052602060ff604060002054166040519015158152f35b346102db5760203660031901126102db5763ffffffff61127a612894565b166000526004602052602060ff60406000205416604051908152f35b346102db5760203660031901126102db576004356000526009602052610120604060002060018060a01b03815416906001600160801b03600182015491600281015482600460038401549301541693604051958652602086015260408501526001600160401b038116606085015260ff8160401c161515608085015261ffff8160481c1660a085015261ffff8160581c1660c085015260681c1660e0830152610100820152f35b346102db5760e03660031901126102db576004356024353660c4116102db5760c4359161ffff8316918284036102db57811580156115ae575b801561158e575b8015611586575b801561157c575b6104985733600052600660205260406000205415610498576001600160801b036113b36129f7565b16158015611559575b8015611536575b8015611508575b61049857600154926113db84612a39565b6001908155600085815260096020908152604080832080546001600160a01b031916331781559384018790556002840186905586835260089091528120546003830180546cffff0000ffffffffffffffffff19166001600160401b03929092169190911760589890981b61ffff60581b16979097176801000000000000000017909655946044905b600281106114aa5750506020945060405191825284820152827f15fad9d1771e99cbbfd09e28642148ef9a495280448869c5a90ec8bae1e1ff0360403393a4604051908152f35b6000805b600281106114c6575087820160050155600101611463565b929060009082356001600160801b03811692838203611505575091602091600193506001600160801b038760071b92831b921b191617920193016114ae565b80fd5b5060a4356001600160801b038116908181036102db57506001600160801b0361152f612a23565b16116113ca565b5061153f612a23565b6001600160801b0380611550612a0d565b169116106113c3565b50611562612a0d565b6001600160801b03806115736129f7565b169116106113bc565b506040831161138b565b508215611384565b5081600052600760205260018060a01b036040600020541633141561137d565b508015611376565b346102db5760203660031901126102db57600435600052600f6020526020604060002054604051908152f35b346102db5760203660031901126102db576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb576000818152600760205260409020546001600160a01b03169081156102ba5780600052600760205260406000206001600160601b0360a01b81541690558060005260086020527f91efe0fbddf615be187704e41356d1a0c8b7c934c5fcabd77c71dadb32f00358602060406000206116a76001600160401b038254166129da565b906001600160401b0382166001600160401b03198254161790556001600160401b0360405191168152a3005b346102db5760203660031901126102db57600435600052600860205260206001600160401b0360406000205416604051908152f35b346102db5760603660031901126102db5760ff60005416610b77576004356000526009602052604060002060038101805460ff8160401c1615908115611cb5575b8115611c9d575b506102ba57600435600052600d602052604060002060443560005260205260ff60406000205416611c8c5761178d60443560243533600435612a55565b80600052600e6020526001600160401b03604060002054164210156102cb57600052600e60205260406000206001600160401b03198154169055600435600052600d60205260406000206044356000526020526040600020600160ff19825416179055600682015460801c916001600160801b03825460681c16838110611c7b5761181b84611821926128e0565b83612980565b600481016001600160801b0361183a8582845416612960565b166001600160801b031982541617905561ffff825460481c1661ffff8114610b455782546affff000000000000000000191660019190910160481b61ffff60481b161782556001808060a01b03825416910154916001600160401b03807f0000000000000000000000000000000000000000000000000000000000000000168142160111610b4557546001600160401b03166000602435158015611c71575b8015611c38575b8015611c18575b610adb5750600254926118f984612a39565b6002558260005260066020526040600020549463ffffffff60005460081c1690604051966119268861290d565b6004358852336020890152856040890152836060890152602435608089015260443560a089015260c0880152600060e08801526000610100880152600061012088015261014087015260006101608701526001600160401b0342166101808701526001600160401b03807f00000000000000000000000000000000000000000000000000000000000000001681421601166101a0870152826101c08701526101e0860152600161020086015283600052600a6020526040600020948051865560018060a01b03602082015116600187019060018060a01b03166001600160601b0360a01b82541617905560018060a01b03604082015116600287019060018060a01b03166001600160601b0360a01b825416179055606081015160038701556080810151600487015560a0810151600587015560c0810151600687015560e08101516007870155610100810151600481101561048257611a899060088801612b3b565b61012081015160068110156104825786611aaa600a92600860209a016129bb565b611ac56001600160801b03610140850151166008830161310e565b600981016001600160801b038061016086015116166001600160801b031982541617815561018084015181546001600160801b036001600160401b0360c01b6101a088015160c01b16926001600160401b0360801b9060801b1691161717905501906001600160401b03806101c083015116166001600160401b03198354161782556101e08101519063ffffffff60401b83549161020060ff60601b910151151560601b169260401b169064ffffffffff60401b19161717905563ffffffff60005460081c169060405193845285840152602435604084015260443560608401526001600160401b03807f0000000000000000000000000000000000000000000000000000000000000000168142160116608084015260a083015260c08201523390827f08a7e7ee077b43ee75408d116f37fb84c47e1cfe7e91265457013512039d6c0060e060043593a4604051908152f35b5063ffffffff815460081c168152600560205260ff6040822054166118e7565b50426001600160401b03807f000000000000000000000000000000000000000000000000000000000000000016814216011611156118e0565b50604435156118d9565b631217157160e31b60005260046000fd5b63721d2c7d60e11b60005260046000fd5b905061ffff808260581c169160481c16101583611750565b9050611cc0836130b9565b1590611749565b346102db5760203660031901126102db5760043580600052600a602052604060002060ff600a82015460601c16158015611d90575b8015611d5f575b6102ba5760088101805461ff0019166105001790558054611d47575b507fbfec5f0aff1e5c47b5f8ec8afdb3fed880f753daf622e718a9b7c385cf416ddd600080a2005b80611d54611d5992613132565b6131ed565b81611d1f565b5060ff600882015460081c166006811015610482578015159081611d84575b50611d03565b60019150141583611d7e565b50600981015460c01c4210611cfc565b346102db5760003660031901126102db57602060ff600054166040519015158152f35b346102db5760203660031901126102db5760043580600052600a60205260406000209060ff600a83015460601c16158015611f02575b8015611eeb575b6102cb576008820160ff815460081c16600681101561048257600114801590611eda575b6102ba5781600052600f6020526040600020549283158015611eca575b611c7b573360005260066020526040600020549081156104985760068101919091556009810180546001600160801b0319166001600160801b038616179055815461ff00191661030017909155600101546040519283526001600160a01b0316917f9f5a10e8d25c68b39aad7500064a8ac8a8458431267fc74cfea14a320bc8cf2290602090a3005b506001600160801b038411611e41565b50600983015460c01c421015611e24565b5060028201546001600160a01b0316331415611e00565b5081541515611df9565b346102db5760003660031901126102db57602063ffffffff60005460081c16604051908152f35b346102db5760203660031901126102db576001600160a01b03611f546128a7565b1660005260066020526020604060002054604051908152f35b346102db57611f7b3661286e565b9060ff60005416610b77576001601254146102ba5760016012558060005260096020526040600020600381019060ff825460401c1615908115612038575b8115612027575b506102ba57611ff490610bfe6001600160801b03851694611fe18633612f41565b6001600160801b03835460681c16612960565b6040519182527f995fe54ed2f5efe5acfcee883c9f3cdff46788cd0d14871c15f69eea22015d1a60203393a36000601255005b61203191506130b9565b1584611fc0565b6001600160801b038516159150611fb9565b346102db5760403660031901126102db576004356001600160401b0381116102db57366023820112156102db578060040135906001600160401b0382116102db578160051b90602482820101913683116102db576024359260ff84168094036102db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb576000946120f0602060405194018461293f565b8252602082019260240190835b8183106122cb575050508051600281109081156122c0575b81156122b5575b81156122ab575b5061229c5783549163ffffffff8360081c1663ffffffff8114612288576001019264ffffffff0063ffffffff85169460081b169064ffffffff0019161785558285526004602052604085208460ff19825416179055845b825181101561221257600581901b8301602001516001600160a01b0316801580156121e8575b6121d9578487526003602090815260408089206001600160a01b0390931689529190528620805460ff191660019081179091550161217a565b63b4fa3fb360e01b8752600487fd5b508487526003602090815260408089206001600160a01b0384168a5290915287205460ff166121a0565b50604080519485526020850181905291519184018290526060840191855b81811061226957602085807fa8e46202f74d95810010d9b0eba20a8a965a8391285ce9ee6e87eb41c052e3468988038aa2604051908152f35b82516001600160a01b0316845260209384019390920191600101612230565b634e487b7160e01b86526011600452602486fd5b63b4fa3fb360e01b8452600484fd5b9050831185612123565b60028510915061211c565b602081119150612115565b82356001600160a01b03811681036122eb578152602092830192016120fd565b8780fd5b346102db5760003660031901126102db5760206040516001600160401b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102db5760003660031901126102db576020600254604051908152f35b346102db5760403660031901126102db576004356024356001600160401b0381168091036102db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5781158015612400575b6104985760207fe06ae3bcd9084813a82ea66e6eacec3e8e03ec3d26e4e2c6a803f840cd593fd29183600052600e82526040600020816001600160401b0319825416179055604051908152a2005b50428111156123b2565b346102db5761241836612858565b90600052600c602052604060002090600052602052602060ff60406000205416604051908152f35b346102db5760003660031901126102db576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346102db5760203660031901126102db5763ffffffff6124a3612894565b166000526005602052602060ff604060002054166040519015158152f35b346102db5760203660031901126102db5760043580156104985733600052600660205280604060002055337f8d8b69f1bb77e4fa4a4dbf1148de1d1b3b3cc9255e919acc37a53ead6b40212f600080a3005b346102db576125213661286e565b9060ff60005416610b77576001601254146102ba57600160125580600052600a602052604060002060ff600a82015460601c1615908115612694575b8115612682575b8115612670575b811561263e575b506102ba5780600052600f6020526001600160801b03604060002054921691826001600160801b03036001600160801b038111610b45576001600160801b031610611c7b576125c18233612f41565b80600052600f60205260406000206125da838254612900565b9055806000526010602052604060002060018060a01b0333166000526020526040600020612609838254612900565b90556040519182527f08db86f4e1cb0e2198df440c670725321f5a649819c04754acdb565dcc90c59160203393a36000601255005b60ff91506008015460081c166006811015610482578015159081612664575b5083612572565b6001915014158361265d565b600981015460c01c421015915061256b565b6001600160801b038416159150612564565b80541515915061255d565b346102db5760203660031901126102db576004358015158091036102db577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036102cb5760207f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec59160ff196000541660ff821617600055604051908152a1005b346102db5761273736612858565b90600052600d602052604060002090600052602052602060ff604060002054166040519015158152f35b346102db5760003660031901126102db576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346102db5760203660031901126102db57600435806000526009602052604060002060018060a01b0381541633141580612825575b6102cb57600301805460ff8160401c16156102ba5768ff0000000000000000191690557f084b873cdb285c0ffe7c178ff857b1c69935dd322c91a660c7ac8bda800dcef5600080a2005b50337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614156127db565b60409060031901126102db576004359060243590565b60409060031901126102db57600435906024356001600160801b03811681036102db5790565b6004359063ffffffff821682036102db57565b600435906001600160a01b03821682036102db57565b602435906001600160a01b03821682036102db57565b9060048210156104825752565b906001600160801b03809116911603906001600160801b038211610b4557565b91908201809211610b4557565b61022081019081106001600160401b0382111761292957604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b0382111761292957604052565b906001600160801b03809116911601906001600160801b038211610b4557565b80546fffffffffffffffffffffffffffffffff60681b191660689290921b6fffffffffffffffffffffffffffffffff60681b16919091179055565b9060068110156104825761ff0082549160081b169061ff001916179055565b6001600160401b03166001600160401b038114610b455760010190565b6044356001600160801b03811681036102db5790565b6064356001600160801b03811681036102db5790565b6084356001600160801b03811681036102db5790565b6000198114610b455760010190565b91908203918211610b4557565b9290918360005260096020526001600160401b03600360406000200154169263ffffffff60005460081c166040519460208601964688523060408801526060870152608086015260a08501526001600160401b037f00000000000000000000000000000000000000000000000000000000000000001660c085015260018060a01b031660e08401526101008301526101208201526101208152612afa6101408261293f565b51902090565b6001600160401b03811161292957601f01601f191660200190565b612b3760409295949360608301961515835260208301906128d3565b0152565b9060048110156104825760ff80198354169116179055565b90929181600052600a602052604060002092600a8401805460ff8160601c1615908115612f23575b8115612f11575b8115612f08575b8115612ee5575b8115612eb8575b506102ba576000848152600b6020908152604080832033845290915290205460ff16612ea75784548015159081612e89575b506102cb576000848152600b60209081526040808320338452825291829020805460ff19166001179055905190810190612c1781612c0986888c87612b1b565b03601f19810183528261293f565b51902084600052600c60205260406000208160005260205260406000209160ff8354169160ff8314610b4557600163ffffffff93019360ff851660ff1982541617905588877fc08b572a950997b2bb69414b8dc0a0243c10ebef137da8d462434bf43907e6ad60405180612c8e8a8c339784612b1b565b0390a45460401c16600052600460205260ff8060406000205416911610612e82578060078501556008840194612cc48387612b3b565b15612e3857604083927f772550e90dca710b0fb450a3e13e2b8b17875e5af5831335797158212fb6c08b9261010061ff0019895416178855612d08835180936128d3565b6020820152a2815480612d1c575b50505050565b6000526009602052604060002090835493600460ff8616101561048257612dbb6001600160801b0393610bfe6003612d7c612e2f99886005607f8360011c168701016080610ff08460041b16915491861b161c1698899160101c166128e0565b92600481016001600160801b03612d9686828454166128e0565b166001600160801b031982541617905501916001600160801b03835460681c16612960565b612dc5838261310e565b6009840180546001600160801b0319166001600160801b038516179055805461ff00191661030017905560018301546040519283526001600160a01b0316917f9f5a10e8d25c68b39aad7500064a8ac8a8458431267fc74cfea14a320bc8cf2290602090a36131ed565b38808080612d16565b9050612e797f2cfe88a88188abcf3e8147252014fcafae5e64035cc180a0c8fab2072ac46462936020939561020061ff0019825416179055611d5481613132565b604051908152a2565b5050505050565b90506000526009602052612ea060406000206130b9565b1538612bc9565b6303af45a960e21b60005260046000fd5b604090811c63ffffffff166000908152600360209081528282203383529052205460ff1615905038612b97565b905063ffffffff8160401c16600052600560205260ff6040600020541690612b90565b83159150612b89565b600987015460c01c4210159150612b82565b905060ff600887015460081c16600681101561048257151590612b7b565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316939291602082602481885afa91821561307857600092613084575b5060249394612fe0602092604051906323b872dd60e01b8583015260018060a01b03168782015230604482015285606482015260648152612fdb60848261293f565b613675565b6040516370a0823160e01b815230600482015294859182905afa92831561307857600093613044575b5080831092831561302f575b50505061301e57565b6312171d8360e31b60005260046000fd5b61303a929350612a48565b1415388080613015565b90926020823d602011613070575b8161305f6020938361293f565b810103126115055750519138613009565b3d9150613052565b6040513d6000823e3d90fd5b90916020823d6020116130b1575b8161309f6020938361293f565b81010312611505575051906024612f99565b3d9150613092565b600181015460008181526007602052604090205482546001600160a01b039081169116149190826130e957505090565b90915060005260086020526001600160401b0360038160406000205416920154161490565b9062010000600160901b0382549160101b169062010000600160901b031916179055565b8054801580156131d5575b6131d15760005260096020526131b6600860406000209201916001600160801b03835460101c166001600160801b0361317d6004840192828454166128e0565b166001600160801b0319825416179055610bfe60036001600160801b03855460101c169201916001600160801b03835460681c16612960565b805471ffffffffffffffffffffffffffffffff000019169055565b5050565b506001600160801b03600883015460101c161561313d565b548015613239576000526009602052600360406000200161ffff815460481c169081156102ba57613237916000190161ffff60481b82549160481b169061ffff60481b1916179055565b565b50565b9081600052600a60205260406000209060ff600a83015460601c161580156133a3575b8015613385575b8015613370575b6102ba576001600160801b03600983015416906008830161040061ff00198254161790558254151560001461335b578254600052600960205260046040600020016001600160801b036132c384828454166128e0565b166001600160801b03198254161790555b6132de82826133ba565b6040519182526001600160a01b031690339084907f56a43be815d86b39dc4d398124c956790410b5e9cf70d477de0299f25fc1831390602090a461332181613751565b1561332f57613237916135e8565b60030154907ff3c0e221c17643f4f2d5f37d5aa7fed18c5ee55c2860680d80799babc7c075ec600080a3565b83600052600f602052600060408120556132d4565b506001600160801b036009830154161561326d565b5060ff600883015460081c1660068110156104825760031415613266565b5060018201546001600160a01b031633141561325f565b6040516370a0823160e01b815230600482015291907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316602084602481845afa938415613078576000946135b4575b506040516370a0823160e01b81526001600160a01b0390921660048301819052602083602481855afa92831561307857600093613580575b5061347860405163a9059cbb60e01b602082015282602482015285604482015260448152612fdb60648261293f565b6040516370a0823160e01b815230600482015290602082602481865afa9182156130785760009261354b575b506020906024604051809581936370a0823160e01b835260048301525afa91821561307857600092613517575b508481119485156134ff575b505083156134f5575b831561302f5750505061301e57565b81811093506134e6565b849295509061350d91612a48565b14159238806134dd565b90916020823d602011613543575b816135326020938361293f565b8101031261150557505190386134d1565b3d9150613525565b90916020823d602011613578575b816135666020938361293f565b810103126115055750519060206134a4565b3d9150613559565b90926020823d6020116135ac575b8161359b6020938361293f565b810103126115055750519138613449565b3d915061358e565b90936020823d6020116135e0575b816135cf6020938361293f565b810103126115055750519238613411565b3d91506135c2565b80600052601160205260ff604060002054166102ba576002820180546001600160a01b0316600090815260066020526040902054928315610498576006018390556000828152601160205260408120805460ff1916600117905590546001600160a01b031691907f8602905161aae8f4629b90f661645ab49c43e18661ab6b353be8ce8f81c9fed99080a4565b8051600091829190602001827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af13d15613749573d906136be82612b00565b916136cc604051938461293f565b82523d6000602084013e5b15908115613728575b81156136ee575b5061301e57565b805160208114925082613704575b5050386136e7565b81925090602091810103126102db57602001518015908115036102db5738806136fc565b80915051801515908161373d575b50906136e0565b60209150141538613736565b6060906136d7565b8054156137b057600381015460008181526007602052604090205460028301546001600160a01b0390811691161491908261378b57505090565b90915060005260086020526001600160401b03600a8160406000205416920154161490565b5060019056fea26469706673582212208806b5f4670884dc0279ac0fecca1ece742bb4cb46c701e73e4b2c5651811d7564736f6c63430008210033" +} diff --git a/contracts-proofvault/attestations/reproducible-build.json b/contracts-proofvault/attestations/reproducible-build.json new file mode 100644 index 0000000..69ad665 --- /dev/null +++ b/contracts-proofvault/attestations/reproducible-build.json @@ -0,0 +1,29 @@ +{ + "schema": "h1dr4.proofvault-reproducible-build/v1", + "clean_builds": 2, + "install_command": "npm ci --ignore-scripts", + "compile_command": "npm run compile", + "node_version": "v22.22.0", + "compiler": "0.8.33+commit.64118f21.Emscripten.clang", + "compiler_settings": { + "evmVersion": "paris", + "viaIR": true, + "optimizer": { + "enabled": true, + "runs": 200 + } + }, + "release_inputs_sha256": { + "H1DR4ProofVault.sol": "a18f95c1f3023e455ad3a0a6b282ffa6d7dd6f539a0b56e0528e2d64935473e2", + "package.json": "70f0788fa37ab6b5cafa810db7f0ad52c245a3d6799701161baa8a5556813f16", + "package-lock.json": "068b53195415ba7a133e260bc1fcae33b0738d90447722d9b352aacb4bf1cc81", + "scripts/compile.mjs": "c783ceab7b2afba393ab0af7eb97bd3f12d0ab3691272b225076dfefd0d57de9", + "scripts/attest-reproducible-build.mjs": "c1cca0d7c590eef8b70010752828ab8cafb5b817ad1faa2c0da44b6b9ec7e2af", + "scripts/deploy-base.mjs": "9b8e770e69849f906452c43456a5ee6c9413014cb6459062793b665e2f39a168", + "test/evm.mjs": "6d86117babb6c9ca05f529c49710d409c6d05e4e54df707cb3ac084c14072924" + }, + "source_sha256": "a18f95c1f3023e455ad3a0a6b282ffa6d7dd6f539a0b56e0528e2d64935473e2", + "artifact_sha256": "583e4477b08539e85da5e3c97c4affb26b7fe2cffedc6a8e3ce06829f1f2fca7", + "creation_bytecode_sha256": "eb0c2f14d95a42e49323c516e76c8d9d0f403e4d2006735fdaff3371391850fa", + "runtime_template_sha256": "4296adaaa38b40b23787b6d78b9fb0bb8a4416ddf97d77b49f77c3fd66dd16de" +} diff --git a/contracts-proofvault/package-lock.json b/contracts-proofvault/package-lock.json new file mode 100644 index 0000000..e3d35be --- /dev/null +++ b/contracts-proofvault/package-lock.json @@ -0,0 +1,4145 @@ +{ + "name": "@h1dr4/proofvault-contracts", + "version": "0.5.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@h1dr4/proofvault-contracts", + "version": "0.5.0", + "dependencies": { + "ethers": "6.17.0" + }, + "devDependencies": { + "ganache": "7.9.2", + "solc": "0.8.33" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "license": "MIT" + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ethers": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", + "integrity": "sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.11.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.21.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/ganache": { + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.9.2.tgz", + "integrity": "sha512-7gsVVDpO9AhrFyDMWWl7SpMsPpqGcnAzjxz3k32LheIPNd64p2XsY9GYRdhWmKuryb60W1iaWPZWDkFKlbRWHA==", + "bundleDependencies": [ + "@trufflesuite/bigint-buffer", + "keccak", + "leveldown", + "secp256k1" + ], + "dev": true, + "hasShrinkwrap": true, + "license": "MIT", + "dependencies": { + "@trufflesuite/bigint-buffer": "1.1.10", + "@trufflesuite/uws-js-unofficial": "20.30.0-unofficial.0", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "5.1.1", + "@types/seedrandom": "3.0.1", + "abstract-level": "1.0.3", + "abstract-leveldown": "7.2.0", + "async-eventemitter": "0.2.4", + "emittery": "0.10.0", + "keccak": "3.0.2", + "leveldown": "6.1.0", + "secp256k1": "4.0.3" + }, + "bin": { + "ganache": "dist/node/cli.js", + "ganache-cli": "dist/node/cli.js" + }, + "optionalDependencies": { + "bufferutil": "4.0.5", + "utf-8-validate": "5.0.7" + } + }, + "node_modules/ganache/node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "extraneous": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ganache/node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "extraneous": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/ganache/node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "extraneous": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ganache/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "extraneous": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ganache/node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "extraneous": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ganache/node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "extraneous": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ganache/node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "extraneous": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/ganache/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "extraneous": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/ganache/node_modules/@microsoft/api-extractor": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.20.1.tgz", + "integrity": "sha512-T7cqcK+JpvHGOj7cD2ZCCWS7Xgru1uOqZwrV/FSUdyKVs5fopZcbBSuetwD/akst3O7Ypryg3UOLP54S/vnVmA==", + "extraneous": true, + "dependencies": { + "@microsoft/api-extractor-model": "7.16.0", + "@microsoft/tsdoc": "0.13.2", + "@microsoft/tsdoc-config": "~0.15.2", + "@rushstack/node-core-library": "3.45.1", + "@rushstack/rig-package": "0.3.8", + "@rushstack/ts-command-line": "4.10.7", + "colors": "~1.2.1", + "lodash": "~4.17.15", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "source-map": "~0.6.1", + "typescript": "~4.5.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/ganache/node_modules/@microsoft/api-extractor-model": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.16.0.tgz", + "integrity": "sha512-0FOrbNIny8mzBrzQnSIkEjAXk0JMSnPmWYxt3ZDTPVg9S8xIPzB6lfgTg9+Mimu0RKCpGKBpd+v2WcR5vGzyUQ==", + "extraneous": true, + "dependencies": { + "@microsoft/tsdoc": "0.13.2", + "@microsoft/tsdoc-config": "~0.15.2", + "@rushstack/node-core-library": "3.45.1" + } + }, + "node_modules/ganache/node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "extraneous": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ganache/node_modules/@microsoft/tsdoc": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", + "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@microsoft/tsdoc-config": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", + "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", + "extraneous": true, + "dependencies": { + "@microsoft/tsdoc": "0.13.2", + "ajv": "~6.12.6", + "jju": "~1.4.0", + "resolve": "~1.19.0" + } + }, + "node_modules/ganache/node_modules/@microsoft/tsdoc-config/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "extraneous": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "node_modules/ganache/node_modules/@rushstack/node-core-library": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.1.tgz", + "integrity": "sha512-BwdssTNe007DNjDBxJgInHg8ePytIPyT0La7ZZSQZF9+rSkT42AygXPGvbGsyFfEntjr4X37zZSJI7yGzL16cQ==", + "extraneous": true, + "dependencies": { + "@types/node": "12.20.24", + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.17.0", + "semver": "~7.3.0", + "timsort": "~0.3.0", + "z-schema": "~5.0.2" + } + }, + "node_modules/ganache/node_modules/@rushstack/node-core-library/node_modules/@types/node": { + "version": "12.20.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@rushstack/rig-package": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.3.8.tgz", + "integrity": "sha512-MDWg1xovea99PWloSiYMjFcCLsrdjFtYt6aOyHNs5ojn5mxrzR6U9F83hvbQjTWnKPMvZtr0vcek+4n+OQOp3Q==", + "extraneous": true, + "dependencies": { + "resolve": "~1.17.0", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/ganache/node_modules/@rushstack/ts-command-line": { + "version": "4.10.7", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.7.tgz", + "integrity": "sha512-CjS+DfNXUSO5Ab2wD1GBGtUTnB02OglRWGqfaTcac9Jn45V5MeUOsq/wA8wEeS5Y/3TZ2P1k+IWdVDiuOFP9Og==", + "extraneous": true, + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/bigint-buffer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz", + "integrity": "sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw==", + "dev": true, + "hasInstallScript": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "node-gyp-build": "4.4.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/bigint-buffer/node_modules/node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/uws-js-unofficial": { + "version": "20.30.0-unofficial.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/uws-js-unofficial/-/uws-js-unofficial-20.30.0-unofficial.0.tgz", + "integrity": "sha512-r5X0aOQcuT6pLwTRLD+mPnAM/nlKtvIK4Z+My++A8tTOR0qTjNRx8UB8jzRj3D+p9PMAp5LnpCUUGmz7/TppwA==", + "dev": true, + "dependencies": { + "ws": "8.13.0" + }, + "optionalDependencies": { + "bufferutil": "4.0.7", + "utf-8-validate": "6.0.3" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/uws-js-unofficial/node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/uws-js-unofficial/node_modules/utf-8-validate": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.3.tgz", + "integrity": "sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/ganache/node_modules/@trufflesuite/uws-js-unofficial/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "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/ganache/node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@types/abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-q5veSX6zjUy/DlDhR4Y4cU0k2Ar+DT2LUraP00T19WLmTO6Se1djepCCaqU6nQrwcJ5Hyo/CWqxTzrrFg8eqbQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ganache/node_modules/@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "extraneous": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/ganache/node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "extraneous": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/ganache/node_modules/@types/estree": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", + "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/ganache/node_modules/@types/mocha": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", + "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@types/node": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", + "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==", + "dev": true + }, + "node_modules/ganache/node_modules/@types/seedrandom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.1.tgz", + "integrity": "sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw==", + "dev": true + }, + "node_modules/ganache/node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "extraneous": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "extraneous": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/ganache/node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "extraneous": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/ganache/node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "extraneous": true, + "dependencies": { + "envinfo": "^7.7.3" + } + }, + "node_modules/ganache/node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ganache/node_modules/abstract-level/node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ganache/node_modules/abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "extraneous": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ganache/node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "extraneous": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ganache/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "extraneous": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "node_modules/ganache/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ganache/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "extraneous": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/ganache/node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "extraneous": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ganache/node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "extraneous": true, + "dependencies": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "node_modules/ganache/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/ganache/node_modules/async-eventemitter": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", + "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", + "dev": true, + "dependencies": { + "async": "^2.4.0" + } + }, + "node_modules/ganache/node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "extraneous": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/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==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "extraneous": true, + "engines": { + "node": "*" + } + }, + "node_modules/ganache/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "extraneous": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/ganache/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "extraneous": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "extraneous": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ganache/node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "extraneous": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/ganache/node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "extraneous": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/ganache/node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "extraneous": true, + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/ganache/node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "extraneous": true, + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/ganache/node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "extraneous": true, + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/ganache/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/ganache/node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/bufferutil": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", + "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/ganache/node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "extraneous": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "node_modules/ganache/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/caniuse-lite": { + "version": "1.0.30001435", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001435.tgz", + "integrity": "sha512-kdCkUTjR+v4YAJelyiDTqiu82BDr4W4CP5sgTA0ZBmqn30XfS2ZghPLMowik9TPhS+psWJiUNxsqLyurDbmutA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "extraneous": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "extraneous": true, + "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/ganache/node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "extraneous": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ganache/node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "extraneous": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ganache/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "extraneous": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/ganache/node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "extraneous": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/colors": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", + "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", + "extraneous": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "extraneous": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/ganache/node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "extraneous": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/ganache/node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "extraneous": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/ganache/node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "extraneous": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/ganache/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "extraneous": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ganache/node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "extraneous": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ganache/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "extraneous": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ganache/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "extraneous": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "extraneous": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/ganache/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "extraneous": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ganache/node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "extraneous": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/ganache/node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ganache/node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/emittery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", + "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "extraneous": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ganache/node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "extraneous": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ganache/node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "extraneous": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ganache/node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "extraneous": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ganache/node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "extraneous": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/ganache/node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "extraneous": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/ganache/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "extraneous": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/ganache/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "extraneous": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/ganache/node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "extraneous": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/ganache/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "extraneous": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "extraneous": true + }, + "node_modules/ganache/node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "extraneous": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/ganache/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "extraneous": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "extraneous": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/ganache/node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "extraneous": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/ganache/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "extraneous": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/ganache/node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "extraneous": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/ganache/node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/ganache/node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "extraneous": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "node_modules/ganache/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "extraneous": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ganache/node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "extraneous": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/ganache/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "extraneous": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/ganache/node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "extraneous": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "extraneous": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + } + }, + "node_modules/ganache/node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "extraneous": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "extraneous": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "extraneous": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ganache/node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/ganache/node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ganache/node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "extraneous": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ganache/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/ganache/node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "extraneous": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "extraneous": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/ganache/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/ganache/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "extraneous": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ganache/node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "extraneous": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ganache/node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "extraneous": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "extraneous": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/ganache/node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "extraneous": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "extraneous": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "extraneous": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "extraneous": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "extraneous": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/ganache/node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/ganache/node_modules/js-yaml/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "extraneous": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "extraneous": true, + "dependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/ganache/node_modules/keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "dev": true, + "hasInstallScript": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ganache/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/level-concat-iterator": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "catering": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/level-js": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz", + "integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==", + "extraneous": true, + "dependencies": { + "abstract-leveldown": "^7.2.0", + "buffer": "^6.0.3", + "inherits": "^2.0.3", + "ltgt": "^2.1.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/ganache/node_modules/level-supports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ganache/node_modules/leveldown": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", + "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", + "dev": true, + "hasInstallScript": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/ganache/node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "extraneous": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/ganache/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "extraneous": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/ganache/node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "extraneous": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/mcl-wasm": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.9.0.tgz", + "integrity": "sha512-rvU7L/68ZrDk4dpPZteiEqvK9nB/1XbbHmuLK6qIvc4xuuJb/iv1p5X3KEyq6AYatLnc+zbdSlLXTlKgTnCRZQ==", + "extraneous": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/ganache/node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "extraneous": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/ganache/node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "extraneous": true + }, + "node_modules/ganache/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "extraneous": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ganache/node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "extraneous": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/ganache/node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ganache/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/ganache/node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "extraneous": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ganache/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "extraneous": true + }, + "node_modules/ganache/node_modules/mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "extraneous": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/ganache/node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/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==", + "extraneous": true + }, + "node_modules/ganache/node_modules/nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "extraneous": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/ganache/node_modules/napi-macros": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/ganache/node_modules/node-loader": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-1.0.2.tgz", + "integrity": "sha512-myxAxpyMR7knjA4Uzwf3gjxaMtxSWj2vpm9o6AYWWxQ1S3XMBNeG2vzYcp/5eW03cBGfgSxyP+wntP8qhBJNhQ==", + "extraneous": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/ganache/node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "extraneous": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "extraneous": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "extraneous": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "extraneous": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/ganache/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "extraneous": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "extraneous": true, + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/ganache/node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "extraneous": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/ganache/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "extraneous": true, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ganache/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "extraneous": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "extraneous": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "extraneous": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "extraneous": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "extraneous": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "extraneous": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/ganache/node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "extraneous": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/ganache/node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "extraneous": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/ganache/node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "extraneous": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/ganache/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ganache/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "extraneous": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/ganache/node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "extraneous": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "extraneous": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/ganache/node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "extraneous": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "extraneous": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ganache/node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "extraneous": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/ganache/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==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "extraneous": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/ganache/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ganache/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "extraneous": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "extraneous": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/ganache/node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "extraneous": true + }, + "node_modules/ganache/node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "extraneous": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/ganache/node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "extraneous": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/shebang-loader": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shebang-loader/-/shebang-loader-0.0.1.tgz", + "integrity": "sha512-nQvhUHvKyzGK5aqPxHfHB5nlAN2EZ2U61S2G0YrxAuCRU5iGhFcxxRiaAdb18UoRS1zVMhRz4gdQ1xFEg3AOyA==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "extraneous": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ganache/node_modules/shx": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz", + "integrity": "sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA==", + "extraneous": true, + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.4" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "extraneous": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ganache/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "extraneous": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/ganache/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "extraneous": true + }, + "node_modules/ganache/node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "extraneous": true, + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/ganache/node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "extraneous": true, + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/ganache/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/ganache/node_modules/string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "extraneous": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/node_modules/terser": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "extraneous": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/terser-webpack-plugin": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz", + "integrity": "sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g==", + "extraneous": true, + "dependencies": { + "jest-worker": "^27.0.6", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/ganache/node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ganache/node_modules/ts-loader": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz", + "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==", + "extraneous": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/ganache/node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "extraneous": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + } + }, + "node_modules/ganache/node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "extraneous": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ganache/node_modules/typescript": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "extraneous": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ganache/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "extraneous": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ganache/node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "extraneous": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + } + }, + "node_modules/ganache/node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "extraneous": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/ganache/node_modules/utf-8-validate": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", + "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/ganache/node_modules/util": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", + "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "extraneous": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/ganache/node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/ganache/node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "extraneous": true + }, + "node_modules/ganache/node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "extraneous": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ganache/node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "extraneous": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ganache/node_modules/webpack": { + "version": "5.65.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz", + "integrity": "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==", + "extraneous": true, + "dependencies": { + "@types/eslint-scope": "^3.7.0", + "@types/estree": "^0.0.50", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.8.3", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.4", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.2" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ganache/node_modules/webpack-cli": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz", + "integrity": "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==", + "extraneous": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.1.0", + "@webpack-cli/info": "^1.4.0", + "@webpack-cli/serve": "^1.6.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ganache/node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "extraneous": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/ganache/node_modules/webpack-cli/node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "extraneous": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ganache/node_modules/webpack-cli/node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "extraneous": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ganache/node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "extraneous": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ganache/node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "extraneous": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ganache/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "extraneous": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ganache/node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "extraneous": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ganache/node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "extraneous": true + }, + "node_modules/ganache/node_modules/workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "extraneous": true + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "extraneous": true + }, + "node_modules/ganache/node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "extraneous": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/ganache/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "extraneous": true + }, + "node_modules/ganache/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "extraneous": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "extraneous": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ganache/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==", + "extraneous": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ganache/node_modules/z-schema": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.4.tgz", + "integrity": "sha512-gm/lx3hDzJNcLwseIeQVm1UcwhWIKpSB4NqH89pTBtFns4k/HDHudsICtvG05Bvw/Mv3jMyk700y5dadueLHdA==", + "extraneous": true, + "dependencies": { + "commander": "^2.20.3", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solc": { + "version": "0.8.33", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.33.tgz", + "integrity": "sha512-qPdHuAeg+DccqYz4Mq4grc7lOdgLA8wB8meCrMHcVXj70noKZhfAMzOCcOD/4RODZnn+sV3V6fWEyUkeVaBPVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "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 + } + } + } + } +} diff --git a/contracts-proofvault/package.json b/contracts-proofvault/package.json new file mode 100644 index 0000000..05db206 --- /dev/null +++ b/contracts-proofvault/package.json @@ -0,0 +1,19 @@ +{ + "name": "@h1dr4/proofvault-contracts", + "version": "0.5.0", + "private": true, + "type": "module", + "scripts": { + "compile": "node scripts/compile.mjs", + "test": "node test/evm.mjs", + "attest:build": "node scripts/attest-reproducible-build.mjs", + "deploy:base": "node scripts/deploy-base.mjs" + }, + "dependencies": { + "ethers": "6.17.0" + }, + "devDependencies": { + "ganache": "7.9.2", + "solc": "0.8.33" + } +} diff --git a/contracts-proofvault/scripts/attest-reproducible-build.mjs b/contracts-proofvault/scripts/attest-reproducible-build.mjs new file mode 100644 index 0000000..5d039fc --- /dev/null +++ b/contracts-proofvault/scripts/attest-reproducible-build.mjs @@ -0,0 +1,89 @@ +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; + +const packageRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..'); +const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex'); +const buildInputs = [ + 'H1DR4ProofVault.sol', + 'package.json', + 'package-lock.json', + 'scripts/compile.mjs', +]; +const releaseInputs = [ + ...buildInputs, + 'scripts/attest-reproducible-build.mjs', + 'scripts/deploy-base.mjs', + 'test/evm.mjs', +]; + +const buildOnce = (ordinal) => { + const buildRoot = fs.mkdtempSync(path.join(os.tmpdir(), `h1dr4-proofvault-repro-${ordinal}-`)); + try { + for (const input of buildInputs) { + const destination = path.join(buildRoot, input); + fs.mkdirSync(path.dirname(destination), { recursive: true }); + fs.copyFileSync(path.join(packageRoot, input), destination); + } + const install = spawnSync('npm', ['ci', '--ignore-scripts'], { + cwd: buildRoot, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }); + if (install.status !== 0) { + throw new Error(`clean install ${ordinal} failed: ${install.stderr || install.stdout}`); + } + const compile = spawnSync('npm', ['run', 'compile'], { + cwd: buildRoot, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }); + if (compile.status !== 0) { + throw new Error(`clean compile ${ordinal} failed: ${compile.stderr || compile.stdout}`); + } + return fs.readFileSync(path.join(buildRoot, 'artifacts', 'H1DR4ProofVault.build.json')); + } finally { + fs.rmSync(buildRoot, { recursive: true, force: true }); + } +}; + +const releaseArtifact = fs.readFileSync( + path.join(packageRoot, 'artifacts', 'H1DR4ProofVault.build.json'), +); +const firstBuild = buildOnce(1); +const secondBuild = buildOnce(2); +if (!releaseArtifact.equals(firstBuild) || !releaseArtifact.equals(secondBuild)) { + throw new Error('clean release builds are not byte-for-byte reproducible'); +} + +const inputDigests = Object.fromEntries(releaseInputs.map((input) => [ + input, + sha256(fs.readFileSync(path.join(packageRoot, input))), +])); +const artifact = JSON.parse(releaseArtifact); +const attestation = { + schema: 'h1dr4.proofvault-reproducible-build/v1', + clean_builds: 2, + install_command: 'npm ci --ignore-scripts', + compile_command: 'npm run compile', + node_version: process.version, + compiler: artifact.compiler, + compiler_settings: artifact.settings, + release_inputs_sha256: inputDigests, + source_sha256: artifact.source_sha256, + artifact_sha256: sha256(releaseArtifact), + creation_bytecode_sha256: artifact.creation_bytecode_sha256, + runtime_template_sha256: artifact.runtime_template_sha256, +}; +const attestationBytes = Buffer.from(`${JSON.stringify(attestation, null, 2)}\n`); +const attestationDir = path.join(packageRoot, 'attestations'); +fs.mkdirSync(attestationDir, { recursive: true }); +const attestationPath = path.join(attestationDir, 'reproducible-build.json'); +fs.writeFileSync(attestationPath, attestationBytes, { mode: 0o600 }); +console.log(JSON.stringify({ + ...attestation, + attestation_sha256: sha256(attestationBytes), + attestation_path: attestationPath, +}, null, 2)); diff --git a/contracts-proofvault/scripts/compile.mjs b/contracts-proofvault/scripts/compile.mjs new file mode 100644 index 0000000..a151191 --- /dev/null +++ b/contracts-proofvault/scripts/compile.mjs @@ -0,0 +1,61 @@ +import fs from 'node:fs'; +import crypto from 'node:crypto'; +import path from 'node:path'; + +if ('SOLJSON_PATH' in process.env) { + throw new Error('SOLJSON_PATH is forbidden in the release compiler'); +} +const { default: solc } = await import('solc'); +const compile = (input) => solc.compile(input); +const compilerVersion = solc.version(); + +const contractPath = path.resolve('H1DR4ProofVault.sol'); +const source = fs.readFileSync(contractPath, 'utf8'); +const input = { + language: 'Solidity', + sources: { 'H1DR4ProofVault.sol': { content: source } }, + settings: { + evmVersion: 'paris', + viaIR: true, + optimizer: { enabled: true, runs: 200 }, + outputSelection: { + '*': { + '*': [ + 'abi', + 'evm.bytecode.object', + 'evm.deployedBytecode.object', + 'evm.deployedBytecode.immutableReferences', + ], + }, + }, + }, +}; +const output = JSON.parse(compile(JSON.stringify(input))); +const errors = (output.errors || []).filter((item) => item.severity === 'error'); +for (const item of output.errors || []) console.error(item.formattedMessage.trim()); +if (errors.length) process.exit(1); +const contract = output.contracts['H1DR4ProofVault.sol'].H1DR4ProofVault; +if (!contract.evm.bytecode.object) throw new Error('empty bytecode'); +if (!contract.evm.deployedBytecode.object) throw new Error('empty runtime bytecode'); +const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex'); +const artifact = { + schema: 'h1dr4.proofvault-build/v1', + contract: 'H1DR4ProofVault', + compiler: compilerVersion, + settings: { evmVersion: 'paris', viaIR: true, optimizer: { enabled: true, runs: 200 } }, + source_sha256: sha256(source), + abi_entries: contract.abi.length, + creation_bytecode_bytes: contract.evm.bytecode.object.length / 2, + creation_bytecode_sha256: sha256(Buffer.from(contract.evm.bytecode.object, 'hex')), + runtime_template_bytes: contract.evm.deployedBytecode.object.length / 2, + runtime_template_sha256: sha256(Buffer.from(contract.evm.deployedBytecode.object, 'hex')), + runtime_immutable_references: contract.evm.deployedBytecode.immutableReferences, +}; +if (artifact.runtime_template_bytes >= 24_576) throw new Error('runtime exceeds EIP-170'); +fs.mkdirSync('artifacts', { recursive: true }); +fs.writeFileSync( + 'artifacts/H1DR4ProofVault.build.json', + `${JSON.stringify({ ...artifact, abi: contract.abi, bytecode: contract.evm.bytecode.object, runtime_template: contract.evm.deployedBytecode.object }, null, 2)}\n`, + { mode: 0o600 }, +); +console.log(JSON.stringify(artifact, null, 2)); diff --git a/contracts-proofvault/scripts/deploy-base.mjs b/contracts-proofvault/scripts/deploy-base.mjs new file mode 100644 index 0000000..90fe194 --- /dev/null +++ b/contracts-proofvault/scripts/deploy-base.mjs @@ -0,0 +1,744 @@ +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; + +import { + Contract, + ContractFactory, + JsonRpcProvider, + Transaction, + Wallet, + getAddress, + getCreateAddress, + keccak256, +} from 'ethers'; + +const BASE_CHAIN_ID = 8453n; +const BASE_USDC = getAddress('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'); +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; +const SENTINEL_MODULES = '0x0000000000000000000000000000000000000001'; +const CONFIRMATION_WORD = 'DEPLOY'; +const EXPECTED_COMPILER = '0.8.33+commit.64118f21.Emscripten.clang'; +const MAX_RELEASE_FEE_PER_GAS = 100_000_000_000n; +const MAX_FINALITY_TIMEOUT_MS = 900_000; +const RPC_URL = process.env.BASE_RPC_URL || 'https://mainnet.base.org'; +const VERIFY_RPC_URL = process.env.BASE_VERIFY_RPC_URL; +const ALLOWED_RPC_ENDPOINTS = new Map([ + ['https://mainnet.base.org/', 'Base public RPC operated under base.org'], + ['https://base-mainnet.public.blastapi.io/', 'Blast public Base endpoint'], +]); +const ALLOWED_RPC_PAIR = ['https://mainnet.base.org/', 'https://base-mainnet.public.blastapi.io/']; + +// Official runtime hashes from safe-global/safe-deployments. +const SAFE_SINGLETONS = new Map(Object.entries({ + '0xd9db270c1b5e3bd161e8c8503c55ceabee709552': { + version: '1.3.0', codeHash: '0xbba688fbdb21ad2bb58bc320638b43d94e7d100f6f3ebaab0a4e4de6304b1c2e', + }, + '0x69f4d1788e39c87893c980c06edf4b7f686e2938': { + version: '1.3.0', codeHash: '0xbba688fbdb21ad2bb58bc320638b43d94e7d100f6f3ebaab0a4e4de6304b1c2e', + }, + '0x3e5c63644e683549055b9be8653de26e0b4cd36e': { + version: '1.3.0', codeHash: '0x21842597390c4c6e3c1239e434a682b054bd9548eee5e9b1d6a4482731023c0f', + }, + '0xfb1bffc9d739b8d520daf37df666da4c687191ea': { + version: '1.3.0', codeHash: '0x21842597390c4c6e3c1239e434a682b054bd9548eee5e9b1d6a4482731023c0f', + }, + '0x41675c099f32341bf84bfc5382af534df5c7461a': { + version: '1.4.1', codeHash: '0x1fe2df852ba3299d6534ef416eefa406e56ced995bca886ab7a553e6d0c5e1c4', + }, + '0x29fcb43b46531bca003ddc8fcb67ffe91900c762': { + version: '1.4.1', codeHash: '0xb1f926978a0f44a2c0ec8fe822418ae969bd8c3f18d61e5103100339894f81ff', + }, +})); +const SAFE_PROXY_RUNTIME_HASHES = new Map([ + ['1.3.0', '0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000'], + ['1.4.1', '0xd7d408ebcd99b2b70be43e20253d6d92a8ea8fab29bd3be7f55b10032331fb4c'], +]); +const SAFE_FALLBACK_HANDLERS = new Map(Object.entries({ + '1.3.0': new Map(Object.entries({ + '0xf48f2b2d2a534e402487b3ee7c18c33aec0fe5e4': + '0x03e69f7ce809e81687c69b19a7d7cca45b6d551ffdec73d9bb87178476de1abf', + '0x017062a1de2fe6b99be3d9d37841fed19f573804': + '0x03e69f7ce809e81687c69b19a7d7cca45b6d551ffdec73d9bb87178476de1abf', + })), + '1.4.1': new Map(Object.entries({ + '0xfd0732dc9e303f09fcef3a7388ad10a83459ec99': + '0x7c6007a5d711cea8dfd5d91f5940ec29c7f200fe511eb1fc1397b367af3c42f9', + })), +})); +const SAFE_FALLBACK_HANDLER_SLOT = + '0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5'; +const SAFE_GUARD_SLOT = + '0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8'; +const SAFE_MODULE_GUARD_SLOT = + '0xb104e0b93118902c651344349b610029d694cfdec91c589c91ebafbcd0289947'; + +const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex'); +const requireAddress = (value, label) => { + if (!value) throw new Error(`${label} is required`); + return getAddress(value.trim()); +}; +const parsePositiveBigInt = (value, label) => { + if (!value || !/^\d+$/.test(value)) throw new Error(`${label} must be an unsigned integer`); + const parsed = BigInt(value); + if (parsed <= 0n) throw new Error(`${label} must be positive`); + return parsed; +}; +const parsePositiveInteger = (value, label, maximum = Number.MAX_SAFE_INTEGER) => { + const parsed = Number(parsePositiveBigInt(value, label)); + if (!Number.isSafeInteger(parsed) || parsed > maximum) { + throw new Error(`${label} exceeds its release limit`); + } + return parsed; +}; +const requireSha256 = (value, label, required = false) => { + const normalized = value?.trim().toLowerCase(); + if (!normalized) { + if (required) throw new Error(`${label} is required`); + return null; + } + if (!/^[0-9a-f]{64}$/.test(normalized)) throw new Error(`${label} must be a SHA-256 digest`); + return normalized; +}; +const hexToBuffer = (value, label) => { + const normalized = value.startsWith('0x') ? value.slice(2) : value; + if (!normalized || normalized.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(normalized)) { + throw new Error(`${label} is not valid bytecode`); + } + return Buffer.from(normalized, 'hex'); +}; +const storageAddress = (value) => getAddress(`0x${value.slice(-40)}`); +const canonicalize = (value) => { + if (Array.isArray(value)) return value.map(canonicalize); + if (value && typeof value === 'object') { + return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalize(value[key])])); + } + return value; +}; +const canonicalJson = (value) => JSON.stringify(canonicalize(value)); +const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)); + +let rpcRequestId = 0; +const rawRpc = async (url, method, params = []) => { + for (let attempt = 0; attempt < 4; attempt += 1) { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), 15_000); + let response; + try { + response = await fetch(url, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ jsonrpc: '2.0', id: ++rpcRequestId, method, params }), + redirect: 'error', + signal: controller.signal, + }); + } catch (error) { + clearTimeout(timer); + if (attempt === 3) throw new Error(`${method} network failure: ${error.message}`); + await sleep(500 * (2 ** attempt)); + continue; + } + clearTimeout(timer); + if (response.ok) { + const body = await response.json(); + if (body.error) throw new Error(`${method} failed: ${body.error.message || 'RPC error'}`); + return body.result; + } + if (![408, 429, 500, 502, 503, 504].includes(response.status) || attempt === 3) { + throw new Error(`${method} failed with HTTP ${response.status}`); + } + await sleep(500 * (2 ** attempt)); + } + throw new Error(`${method} exhausted RPC retries`); +}; + +if (!VERIFY_RPC_URL) throw new Error('BASE_VERIFY_RPC_URL is required'); +const primaryUrl = new URL(RPC_URL); +const verifyUrl = new URL(VERIFY_RPC_URL); +for (const endpoint of [primaryUrl, verifyUrl]) { + if (endpoint.protocol !== 'https:' || endpoint.username || endpoint.password + || endpoint.search || endpoint.hash) { + throw new Error('Base RPC endpoints must be credential-free exact HTTPS URLs'); + } +} +if (primaryUrl.href !== ALLOWED_RPC_PAIR[0] || verifyUrl.href !== ALLOWED_RPC_PAIR[1]) { + throw new Error(`release RPC pair must be exactly ${ALLOWED_RPC_PAIR.join(' and ')}`); +} + +const provider = new JsonRpcProvider(RPC_URL, Number(BASE_CHAIN_ID), { staticNetwork: true }); +const verifyProvider = new JsonRpcProvider(VERIFY_RPC_URL, Number(BASE_CHAIN_ID), { staticNetwork: true }); + +const getCommonFinalizedBlock = async (pinnedBlock = null) => { + const [primaryHead, verifyHead] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getBlockByNumber', ['finalized', false]), + rawRpc(VERIFY_RPC_URL, 'eth_getBlockByNumber', ['finalized', false]), + ]); + if (!primaryHead?.number || !primaryHead?.hash || !verifyHead?.number || !verifyHead?.hash) { + throw new Error('both RPC endpoints must expose finalized Base blocks'); + } + const primaryHeight = BigInt(primaryHead.number); + const verifyHeight = BigInt(verifyHead.number); + const selectedHeight = pinnedBlock ?? (primaryHeight < verifyHeight ? primaryHeight : verifyHeight); + if (primaryHeight < selectedHeight || verifyHeight < selectedHeight) { + throw new Error('pinned corroboration block is not finalized on both RPC endpoints'); + } + const blockTag = `0x${selectedHeight.toString(16)}`; + const [primaryBlock, verifyBlock] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getBlockByNumber', [blockTag, false]), + rawRpc(VERIFY_RPC_URL, 'eth_getBlockByNumber', [blockTag, false]), + ]); + if (!primaryBlock?.hash || primaryBlock.hash !== verifyBlock?.hash) { + throw new Error('RPC endpoints disagree on the common finalized Base block'); + } + return { + number: selectedHeight, + blockTag, + hash: primaryBlock.hash, + primaryFinalizedHeight: primaryHeight, + verifyFinalizedHeight: verifyHeight, + }; +}; + +const [primaryChainHex, verifyChainHex] = await Promise.all([ + rawRpc(RPC_URL, 'eth_chainId'), rawRpc(VERIFY_RPC_URL, 'eth_chainId'), +]); +if (BigInt(primaryChainHex) !== BASE_CHAIN_ID || BigInt(verifyChainHex) !== BASE_CHAIN_ID) { + throw new Error('both RPC endpoints must report Base mainnet chain ID 8453'); +} +const pinnedCorroborationBlock = process.env.PROOFVAULT_CORROBORATION_BLOCK + ? parsePositiveBigInt(process.env.PROOFVAULT_CORROBORATION_BLOCK, 'PROOFVAULT_CORROBORATION_BLOCK') + : null; +const corroboration = await getCommonFinalizedBlock(pinnedCorroborationBlock); + +const [primaryTokenCode, verifyTokenCode] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getCode', [BASE_USDC, corroboration.blockTag]), + rawRpc(VERIFY_RPC_URL, 'eth_getCode', [BASE_USDC, corroboration.blockTag]), +]); +if (primaryTokenCode === '0x' || primaryTokenCode !== verifyTokenCode) { + throw new Error('independent RPCs do not agree on canonical Base USDC code'); +} +const tokenAbi = ['function decimals() view returns (uint8)', 'function symbol() view returns (string)']; +const readToken = async (readProvider) => { + const token = new Contract(BASE_USDC, tokenAbi, readProvider); + return { + decimals: Number(await token.decimals({ blockTag: corroboration.blockTag })), + symbol: await token.symbol({ blockTag: corroboration.blockTag }), + }; +}; +const [tokenReadback, verifyTokenReadback] = await Promise.all([readToken(provider), readToken(verifyProvider)]); +if (canonicalJson(tokenReadback) !== canonicalJson(verifyTokenReadback) + || tokenReadback.decimals !== 6 || tokenReadback.symbol !== 'USDC') { + throw new Error('canonical Base USDC metadata mismatch'); +} + +const packageRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..'); +const source = fs.readFileSync(path.join(packageRoot, 'H1DR4ProofVault.sol')); +const packageLock = fs.readFileSync(path.join(packageRoot, 'package-lock.json')); +const artifactPath = path.join(packageRoot, 'artifacts', 'H1DR4ProofVault.build.json'); +const artifactBytes = fs.readFileSync(artifactPath); +const artifact = JSON.parse(artifactBytes); +const reproducibleBuildAttestationPath = path.join( + packageRoot, 'attestations', 'reproducible-build.json', +); +const reproducibleBuildAttestationBytes = fs.existsSync(reproducibleBuildAttestationPath) + ? fs.readFileSync(reproducibleBuildAttestationPath) + : null; +const reproducibleBuildAttestation = reproducibleBuildAttestationBytes + ? JSON.parse(reproducibleBuildAttestationBytes) + : null; +const actualSourceSha256 = sha256(source); +const actualArtifactSha256 = sha256(artifactBytes); +if (artifact.schema !== 'h1dr4.proofvault-build/v1' + || artifact.contract !== 'H1DR4ProofVault' || artifact.compiler !== EXPECTED_COMPILER + || artifact.settings?.evmVersion !== 'paris' || artifact.settings?.viaIR !== true + || artifact.settings?.optimizer?.enabled !== true || artifact.settings?.optimizer?.runs !== 200) { + throw new Error('build artifact compiler/settings mismatch'); +} +if (artifact.source_sha256 !== actualSourceSha256) throw new Error('stale build artifact'); +const creationBytecode = hexToBuffer(artifact.bytecode, 'creation bytecode'); +const runtimeTemplate = hexToBuffer(artifact.runtime_template, 'runtime template'); +if (artifact.creation_bytecode_bytes !== creationBytecode.length + || artifact.creation_bytecode_sha256 !== sha256(creationBytecode) + || artifact.runtime_template_bytes !== runtimeTemplate.length + || artifact.runtime_template_sha256 !== sha256(runtimeTemplate) + || runtimeTemplate.length >= 24_576) throw new Error('build artifact bytecode integrity mismatch'); +for (const entries of Object.values(artifact.runtime_immutable_references || {})) { + for (const { start, length } of entries) { + if (!Number.isInteger(start) || !Number.isInteger(length) || start < 0 || length < 1 + || start + length > runtimeTemplate.length) throw new Error('invalid immutable reference in build artifact'); + } +} + +const expectedSourceSha256 = requireSha256( + process.env.PROOFVAULT_EXPECTED_SOURCE_SHA256, 'PROOFVAULT_EXPECTED_SOURCE_SHA256', +); +const expectedArtifactSha256 = requireSha256( + process.env.PROOFVAULT_EXPECTED_ARTIFACT_SHA256, 'PROOFVAULT_EXPECTED_ARTIFACT_SHA256', +); +const reproducibleBuildAttestationSha256 = requireSha256( + process.env.PROOFVAULT_REPRODUCIBLE_BUILD_ATTESTATION_SHA256, + 'PROOFVAULT_REPRODUCIBLE_BUILD_ATTESTATION_SHA256', +); +if (expectedSourceSha256 && expectedSourceSha256 !== actualSourceSha256) { + throw new Error('externally pinned source digest mismatch'); +} +if (expectedArtifactSha256 && expectedArtifactSha256 !== actualArtifactSha256) { + throw new Error('externally pinned build artifact digest mismatch'); +} +if (reproducibleBuildAttestationSha256) { + if (!reproducibleBuildAttestationBytes + || sha256(reproducibleBuildAttestationBytes) !== reproducibleBuildAttestationSha256) { + throw new Error('reproducible-build attestation file digest mismatch'); + } + if (reproducibleBuildAttestation?.schema !== 'h1dr4.proofvault-reproducible-build/v1' + || reproducibleBuildAttestation.clean_builds !== 2 + || reproducibleBuildAttestation.source_sha256 !== actualSourceSha256 + || reproducibleBuildAttestation.artifact_sha256 !== actualArtifactSha256 + || reproducibleBuildAttestation.release_inputs_sha256?.['package-lock.json'] + !== sha256(packageLock) + || reproducibleBuildAttestation.release_inputs_sha256?.['scripts/deploy-base.mjs'] + !== sha256(fs.readFileSync(path.join(packageRoot, 'scripts', 'deploy-base.mjs'))) + || reproducibleBuildAttestation.release_inputs_sha256?.['test/evm.mjs'] + !== sha256(fs.readFileSync(path.join(packageRoot, 'test', 'evm.mjs')))) { + throw new Error('reproducible-build attestation does not bind this release package'); + } +} +const securityScanId = process.env.PROOFVAULT_SECURITY_SCAN_ID?.trim() || null; +const securitySnapshotDigest = process.env.PROOFVAULT_SECURITY_SNAPSHOT_DIGEST?.trim() || null; +if (securityScanId && !/^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(securityScanId)) { + throw new Error('PROOFVAULT_SECURITY_SCAN_ID must be a scan UUID'); +} +if (securitySnapshotDigest + && !/^codex-security-snapshot\/v1:sha256:[0-9a-f]{64}$/.test(securitySnapshotDigest)) { + throw new Error('PROOFVAULT_SECURITY_SNAPSHOT_DIGEST has an invalid format'); +} + +const initialGovernor = requireAddress(process.env.PROOFVAULT_GOVERNOR, 'PROOFVAULT_GOVERNOR'); +const safeAbi = [ + 'function VERSION() view returns (string)', + 'function getOwners() view returns (address[])', + 'function getThreshold() view returns (uint256)', + 'function getModulesPaginated(address start,uint256 pageSize) view returns (address[] array,address next)', +]; +const readSafeInterface = async (readProvider, blockTag) => { + const safe = new Contract(initialGovernor, safeAbi, readProvider); + const modulesPage = await safe.getModulesPaginated(SENTINEL_MODULES, 100, { blockTag }); + return { + version: await safe.VERSION({ blockTag }), + owners: (await safe.getOwners({ blockTag })).map(getAddress), + threshold: Number(await safe.getThreshold({ blockTag })), + modules: modulesPage[0].map(getAddress), + modules_next: getAddress(modulesPage[1]), + }; +}; +const readSafeRaw = async (url, blockTag) => { + const [proxyCode, singletonSlot, fallbackSlot, guardSlot, moduleGuardSlot] = await Promise.all([ + rawRpc(url, 'eth_getCode', [initialGovernor, blockTag]), + rawRpc(url, 'eth_getStorageAt', [initialGovernor, '0x0', blockTag]), + rawRpc(url, 'eth_getStorageAt', [initialGovernor, SAFE_FALLBACK_HANDLER_SLOT, blockTag]), + rawRpc(url, 'eth_getStorageAt', [initialGovernor, SAFE_GUARD_SLOT, blockTag]), + rawRpc(url, 'eth_getStorageAt', [initialGovernor, SAFE_MODULE_GUARD_SLOT, blockTag]), + ]); + return { + proxy_code: proxyCode, + proxy_code_hash: proxyCode === '0x' ? null : keccak256(proxyCode), + singleton: storageAddress(singletonSlot), + fallback_handler: storageAddress(fallbackSlot), + guard: storageAddress(guardSlot), + module_guard: storageAddress(moduleGuardSlot), + }; +}; +const verifySafeState = async (blockTag) => { + let primaryInterface; let verifyInterface; let primaryRaw; let verifyRaw; + try { + [primaryInterface, verifyInterface, primaryRaw, verifyRaw] = await Promise.all([ + readSafeInterface(provider, blockTag), readSafeInterface(verifyProvider, blockTag), + readSafeRaw(RPC_URL, blockTag), readSafeRaw(VERIFY_RPC_URL, blockTag), + ]); + } catch (error) { + throw new Error(`initial governor does not pass the required Safe interface: ${error.message}`); + } + if (canonicalJson(primaryInterface) !== canonicalJson(verifyInterface) + || canonicalJson(primaryRaw) !== canonicalJson(verifyRaw)) { + throw new Error('RPC endpoints disagree on Safe governance state'); + } + if (primaryRaw.proxy_code === '0x') throw new Error('Safe governor has no runtime code'); + const singletonPolicy = SAFE_SINGLETONS.get(primaryRaw.singleton.toLowerCase()); + if (!singletonPolicy || singletonPolicy.version !== primaryInterface.version) { + throw new Error('Safe singleton is not an allowlisted official deployment'); + } + const [primarySingletonCode, verifySingletonCode] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getCode', [primaryRaw.singleton, blockTag]), + rawRpc(VERIFY_RPC_URL, 'eth_getCode', [primaryRaw.singleton, blockTag]), + ]); + if (primarySingletonCode === '0x' || primarySingletonCode !== verifySingletonCode + || keccak256(primarySingletonCode) !== singletonPolicy.codeHash) { + throw new Error('Safe singleton runtime does not match the official deployment hash'); + } + if (primaryRaw.proxy_code_hash !== SAFE_PROXY_RUNTIME_HASHES.get(primaryInterface.version)) { + throw new Error( + `Safe proxy runtime hash ${primaryRaw.proxy_code_hash} is not allowlisted for ${primaryInterface.version}`, + ); + } + if (primaryInterface.owners.length < 2 + || new Set(primaryInterface.owners).size !== primaryInterface.owners.length + || primaryInterface.threshold < 2 || primaryInterface.threshold > primaryInterface.owners.length) { + throw new Error('governor Safe must enforce at least a 2-of-N owner threshold'); + } + if (primaryInterface.modules.length !== 0 + || primaryInterface.modules_next !== getAddress(SENTINEL_MODULES) + || primaryRaw.guard !== ZERO_ADDRESS || primaryRaw.module_guard !== ZERO_ADDRESS) { + throw new Error('governor Safe must have no modules, guard, or module guard'); + } + let fallbackHandlerCodeHash = null; + if (primaryRaw.fallback_handler !== ZERO_ADDRESS) { + const fallbackPolicy = SAFE_FALLBACK_HANDLERS + .get(primaryInterface.version)?.get(primaryRaw.fallback_handler.toLowerCase()); + if (!fallbackPolicy) throw new Error('Safe fallback handler is not allowlisted'); + const [primaryFallbackCode, verifyFallbackCode] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getCode', [primaryRaw.fallback_handler, blockTag]), + rawRpc(VERIFY_RPC_URL, 'eth_getCode', [primaryRaw.fallback_handler, blockTag]), + ]); + if (primaryFallbackCode === '0x' || primaryFallbackCode !== verifyFallbackCode + || keccak256(primaryFallbackCode) !== fallbackPolicy) { + throw new Error('Safe fallback handler runtime does not match the official deployment hash'); + } + fallbackHandlerCodeHash = fallbackPolicy; + } + return { + version: primaryInterface.version, + owners: primaryInterface.owners, + threshold: primaryInterface.threshold, + singleton: primaryRaw.singleton, + singleton_code_hash: singletonPolicy.codeHash, + proxy_code_hash: primaryRaw.proxy_code_hash, + modules: primaryInterface.modules, + guard: primaryRaw.guard, + module_guard: primaryRaw.module_guard, + fallback_handler: primaryRaw.fallback_handler, + fallback_handler_code_hash: fallbackHandlerCodeHash, + }; +}; +const safeReadback = await verifySafeState(corroboration.blockTag); + +const privateKey = process.env.DEPLOYER_PRIVATE_KEY?.trim(); +const configuredDeployer = process.env.DEPLOYER_ADDRESS?.trim(); +const wallet = privateKey ? new Wallet(privateKey, provider) : null; +const deployer = wallet ? wallet.address : requireAddress(configuredDeployer, 'DEPLOYER_ADDRESS for dry run'); +if (configuredDeployer && getAddress(configuredDeployer) !== deployer) { + throw new Error('DEPLOYER_PRIVATE_KEY does not match DEPLOYER_ADDRESS'); +} +if (deployer === initialGovernor) throw new Error('raw deployer cannot be the governor'); + +const validators = (process.env.PROOFVAULT_VALIDATORS || '') + .split(',').map((value) => value.trim()).filter(Boolean).map(getAddress); +if (validators.length < 2) throw new Error('at least two PROOFVAULT_VALIDATORS are required'); +if (new Set(validators).size !== validators.length) throw new Error('duplicate validator'); +const threshold = Number(process.env.PROOFVAULT_THRESHOLD || ''); +if (!Number.isInteger(threshold) || threshold < 2 || threshold > validators.length) { + throw new Error('PROOFVAULT_THRESHOLD must be 2..validator count'); +} +const decisionWindow = Number(process.env.PROOFVAULT_DECISION_WINDOW || ''); +if (!Number.isInteger(decisionWindow) || decisionWindow < 3_600 || decisionWindow > 2_592_000) { + throw new Error('PROOFVAULT_DECISION_WINDOW must be 3600..2592000 seconds'); +} + +const readPendingNonce = async () => { + const [primaryNonceHex, verifyNonceHex] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getTransactionCount', [deployer, 'pending']), + rawRpc(VERIFY_RPC_URL, 'eth_getTransactionCount', [deployer, 'pending']), + ]); + if (primaryNonceHex !== verifyNonceHex) throw new Error('independent RPCs disagree on deployer pending nonce'); + const nonce = Number(BigInt(primaryNonceHex)); + if (!Number.isSafeInteger(nonce)) throw new Error('deployer nonce exceeds JavaScript safe integer range'); + return nonce; +}; + +const factory = new ContractFactory(artifact.abi, artifact.bytecode); +const unsigned = await factory.getDeployTransaction( + BASE_USDC, initialGovernor, validators, threshold, decisionWindow, +); +if (!unsigned.data) throw new Error('missing deployment init code'); +const pendingNonce = await readPendingNonce(); +const [primaryFinalizedNonceHex, verifyFinalizedNonceHex] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getTransactionCount', [deployer, corroboration.blockTag]), + rawRpc(VERIFY_RPC_URL, 'eth_getTransactionCount', [deployer, corroboration.blockTag]), +]); +if (primaryFinalizedNonceHex !== verifyFinalizedNonceHex) { + throw new Error('independent RPCs disagree on deployer nonce at finalized block'); +} +const estimatedGas = await provider.estimateGas({ data: unsigned.data, from: deployer }); +const gasLimit = (estimatedGas * 120n + 99n) / 100n; +if (gasLimit > 10_000_000n) throw new Error('deployment gas limit exceeds release cap'); +const feeData = await provider.getFeeData(); +const proposedPriorityFee = feeData.maxPriorityFeePerGas || 1_000_000n; +const proposedMaxFee = feeData.maxFeePerGas || feeData.gasPrice; +if (!proposedMaxFee) throw new Error('primary RPC did not return EIP-1559 fee data'); +const maxPriorityFeePerGas = process.env.PROOFVAULT_MAX_PRIORITY_FEE_PER_GAS_WEI + ? parsePositiveBigInt(process.env.PROOFVAULT_MAX_PRIORITY_FEE_PER_GAS_WEI, 'PROOFVAULT_MAX_PRIORITY_FEE_PER_GAS_WEI') + : proposedPriorityFee; +const maxFeePerGas = process.env.PROOFVAULT_MAX_FEE_PER_GAS_WEI + ? parsePositiveBigInt(process.env.PROOFVAULT_MAX_FEE_PER_GAS_WEI, 'PROOFVAULT_MAX_FEE_PER_GAS_WEI') + : proposedMaxFee; +if (maxFeePerGas < maxPriorityFeePerGas || maxFeePerGas > MAX_RELEASE_FEE_PER_GAS) { + throw new Error('invalid or excessive EIP-1559 fee cap'); +} +const estimatedMaxCost = gasLimit * maxFeePerGas; +const nativeBalance = await provider.getBalance(deployer); +const expectedContract = getCreateAddress({ from: deployer, nonce: pendingNonce }); +const initCode = unsigned.data; +const basePlan = { + schema: 'h1dr4.proofvault-deployment-plan/v3', + chain_id: Number(BASE_CHAIN_ID), + rpc_primary: { url: primaryUrl.href, identity: ALLOWED_RPC_ENDPOINTS.get(primaryUrl.href) }, + rpc_verify: { url: verifyUrl.href, identity: ALLOWED_RPC_ENDPOINTS.get(verifyUrl.href) }, + corroboration_block_number: Number(corroboration.number), + corroboration_block_hash: corroboration.hash, + payment_token: BASE_USDC, + payment_token_code_keccak256: keccak256(primaryTokenCode), + initial_governor: initialGovernor, + initial_governor_safe: safeReadback, + deployer, + validators, + threshold, + decision_window_seconds: decisionWindow, + compiler: artifact.compiler, + compiler_settings: artifact.settings, + package_lock_sha256: sha256(packageLock), + build_artifact_sha256: actualArtifactSha256, + externally_pinned_build_artifact_sha256: expectedArtifactSha256, + source_sha256: actualSourceSha256, + externally_pinned_source_sha256: expectedSourceSha256, + reproducible_build_attestation_sha256: reproducibleBuildAttestationSha256, + security_scan_id: securityScanId, + security_snapshot_digest: securitySnapshotDigest, + creation_bytecode_bytes: artifact.creation_bytecode_bytes, + creation_bytecode_sha256: artifact.creation_bytecode_sha256, + runtime_template_bytes: artifact.runtime_template_bytes, + runtime_template_sha256: artifact.runtime_template_sha256, + init_code_bytes: (initCode.length - 2) / 2, + init_code_keccak256: keccak256(initCode), + init_code_sha256: sha256(hexToBuffer(initCode, 'init code')), + expected_contract: expectedContract, + transaction_type: 2, + nonce: pendingNonce, + finalized_nonce: Number(BigInt(primaryFinalizedNonceHex)), + value_wei: '0', + estimated_gas: estimatedGas.toString(), + gas_limit: gasLimit.toString(), + max_fee_per_gas_wei: maxFeePerGas.toString(), + max_priority_fee_per_gas_wei: maxPriorityFeePerGas.toString(), + maximum_cost_wei: estimatedMaxCost.toString(), +}; +const planSha256 = sha256(canonicalJson(basePlan)); +const plan = { + ...basePlan, + plan_sha256: planSha256, + deployer_native_balance_wei: nativeBalance.toString(), + observed_finalized_heights: { + primary: Number(corroboration.primaryFinalizedHeight), + verify: Number(corroboration.verifyFinalizedHeight), + }, + confirmation_required: `CONFIRM_BASE_MAINNET=${CONFIRMATION_WORD} and CONFIRM_PLAN_SHA256=${planSha256}`, +}; + +if (process.env.CONFIRM_BASE_MAINNET !== CONFIRMATION_WORD) { + console.log(JSON.stringify({ + ...plan, + status: 'dry_run', + release_gate_complete: Boolean(expectedSourceSha256 && expectedArtifactSha256 + && reproducibleBuildAttestationSha256 && securityScanId && securitySnapshotDigest), + repeat_with: { + PROOFVAULT_MAX_FEE_PER_GAS_WEI: maxFeePerGas.toString(), + PROOFVAULT_MAX_PRIORITY_FEE_PER_GAS_WEI: maxPriorityFeePerGas.toString(), + PROOFVAULT_CORROBORATION_BLOCK: corroboration.number.toString(), + }, + }, null, 2)); + process.exit(0); +} +if (!wallet) throw new Error('DEPLOYER_PRIVATE_KEY is required for confirmed deployment'); +if (!process.env.PROOFVAULT_MAX_FEE_PER_GAS_WEI + || !process.env.PROOFVAULT_MAX_PRIORITY_FEE_PER_GAS_WEI + || !process.env.PROOFVAULT_CORROBORATION_BLOCK) { + throw new Error('confirmed deployment requires explicit fee caps and corroboration block'); +} +requireSha256(process.env.PROOFVAULT_EXPECTED_SOURCE_SHA256, 'PROOFVAULT_EXPECTED_SOURCE_SHA256', true); +requireSha256(process.env.PROOFVAULT_EXPECTED_ARTIFACT_SHA256, 'PROOFVAULT_EXPECTED_ARTIFACT_SHA256', true); +requireSha256( + process.env.PROOFVAULT_REPRODUCIBLE_BUILD_ATTESTATION_SHA256, + 'PROOFVAULT_REPRODUCIBLE_BUILD_ATTESTATION_SHA256', true, +); +if (!securityScanId || !securitySnapshotDigest) { + throw new Error('confirmed deployment requires an exact completed security scan and snapshot digest'); +} +if (process.env.CONFIRM_PLAN_SHA256 !== planSha256) { + throw new Error(`CONFIRM_PLAN_SHA256 mismatch; reviewed plan is ${planSha256}`); +} +if (nativeBalance < estimatedMaxCost) throw new Error('insufficient native balance for deployment'); +if (await readPendingNonce() !== pendingNonce) throw new Error('deployer pending nonce changed after planning'); +const preSignSafeReadback = await verifySafeState('latest'); +if (canonicalJson(preSignSafeReadback) !== canonicalJson(safeReadback)) { + throw new Error('Safe governance state changed after the reviewed plan'); +} + +const txRequest = { + chainId: BASE_CHAIN_ID, type: 2, nonce: pendingNonce, gasLimit, + maxFeePerGas, maxPriorityFeePerGas, value: 0n, data: initCode, +}; +const signedTransaction = await wallet.signTransaction(txRequest); +const decodedTransaction = Transaction.from(signedTransaction); +if (decodedTransaction.from !== deployer || decodedTransaction.to !== null + || decodedTransaction.chainId !== BASE_CHAIN_ID || decodedTransaction.type !== 2 + || decodedTransaction.nonce !== pendingNonce || decodedTransaction.gasLimit !== gasLimit + || decodedTransaction.maxFeePerGas !== maxFeePerGas + || decodedTransaction.maxPriorityFeePerGas !== maxPriorityFeePerGas + || decodedTransaction.value !== 0n || decodedTransaction.data !== initCode) { + throw new Error('signed transaction does not match reviewed deployment plan'); +} + +const receiptsDir = path.join(packageRoot, 'receipts'); +fs.mkdirSync(receiptsDir, { recursive: true }); +const journalPath = path.join(receiptsDir, `proofvault-base-${decodedTransaction.hash}.broadcast.json`); +const writeJournal = (status, extra = {}) => fs.writeFileSync(journalPath, `${JSON.stringify({ + schema: 'h1dr4.proofvault-broadcast-journal/v1', + status, + plan, + transaction_hash: decodedTransaction.hash, + signed_transaction_sha256: sha256(hexToBuffer(signedTransaction, 'signed transaction')), + ...extra, +}, null, 2)}\n`, { mode: 0o600 }); +writeJournal('signed_not_broadcast'); + +const deploymentTx = await provider.broadcastTransaction(signedTransaction); +if (deploymentTx.hash !== decodedTransaction.hash) throw new Error('broadcast transaction hash mismatch'); +writeJournal('broadcast'); +const txReceipt = await provider.waitForTransaction(deploymentTx.hash, 1, 180_000); +if (!txReceipt || txReceipt.status !== 1) throw new Error('deployment transaction failed'); +if (txReceipt.contractAddress !== expectedContract || txReceipt.blockHash == null) { + throw new Error('deployment address or block hash differs from plan'); +} +writeJournal('mined_awaiting_finality', { block_number: txReceipt.blockNumber, block_hash: txReceipt.blockHash }); +const verifyReceipt = await verifyProvider.waitForTransaction(deploymentTx.hash, 1, 180_000); +if (!verifyReceipt || verifyReceipt.status !== 1 + || verifyReceipt.blockNumber !== txReceipt.blockNumber || verifyReceipt.blockHash !== txReceipt.blockHash + || verifyReceipt.contractAddress !== expectedContract) { + throw new Error('independent RPC does not corroborate the deployment receipt'); +} + +const finalityTimeoutMs = process.env.PROOFVAULT_FINALITY_TIMEOUT_MS + ? parsePositiveInteger(process.env.PROOFVAULT_FINALITY_TIMEOUT_MS, 'PROOFVAULT_FINALITY_TIMEOUT_MS', MAX_FINALITY_TIMEOUT_MS) + : 600_000; +const waitForFinalizedInclusion = async () => { + const deadline = Date.now() + finalityTimeoutMs; + const deploymentHeight = BigInt(txReceipt.blockNumber); + while (Date.now() <= deadline) { + const [primaryHead, verifyHead] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getBlockByNumber', ['finalized', false]), + rawRpc(VERIFY_RPC_URL, 'eth_getBlockByNumber', ['finalized', false]), + ]); + if (primaryHead?.number && verifyHead?.number + && BigInt(primaryHead.number) >= deploymentHeight && BigInt(verifyHead.number) >= deploymentHeight) { + const blockTag = `0x${deploymentHeight.toString(16)}`; + const [primaryBlock, verifyBlock] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getBlockByNumber', [blockTag, false]), + rawRpc(VERIFY_RPC_URL, 'eth_getBlockByNumber', [blockTag, false]), + ]); + if (primaryBlock?.hash !== txReceipt.blockHash || verifyBlock?.hash !== txReceipt.blockHash) { + throw new Error('finalized deployment block hash differs from the mined receipt'); + } + return { + primary_finalized_height: Number(BigInt(primaryHead.number)), + verify_finalized_height: Number(BigInt(verifyHead.number)), + }; + } + await sleep(5_000); + } + throw new Error(`deployment mined but did not finalize within ${finalityTimeoutMs} ms; inspect ${journalPath}`); +}; +const finality = await waitForFinalizedInclusion(); + +const [primaryBlock, verifyBlock, sentTransaction, verifyTransaction] = await Promise.all([ + provider.getBlock(txReceipt.blockNumber), verifyProvider.getBlock(txReceipt.blockNumber), + provider.getTransaction(deploymentTx.hash), verifyProvider.getTransaction(deploymentTx.hash), +]); +if (!primaryBlock || !verifyBlock || primaryBlock.hash !== txReceipt.blockHash + || verifyBlock.hash !== txReceipt.blockHash || !sentTransaction || !verifyTransaction + || sentTransaction.data !== initCode || verifyTransaction.data !== initCode + || sentTransaction.nonce !== pendingNonce || verifyTransaction.nonce !== pendingNonce) { + throw new Error('independent block or transaction corroboration failed'); +} + +const finalizedDeploymentBlockTag = `0x${BigInt(txReceipt.blockNumber).toString(16)}`; +const [runtimeHex, verifyRuntimeHex] = await Promise.all([ + rawRpc(RPC_URL, 'eth_getCode', [expectedContract, finalizedDeploymentBlockTag]), + rawRpc(VERIFY_RPC_URL, 'eth_getCode', [expectedContract, finalizedDeploymentBlockTag]), +]); +if (runtimeHex === '0x' || runtimeHex !== verifyRuntimeHex) { + throw new Error('independent RPCs do not agree on deployed runtime'); +} +const runtime = hexToBuffer(runtimeHex, 'deployed runtime'); +if (runtime.length !== runtimeTemplate.length) throw new Error('runtime byte length mismatch'); +const maskedRuntime = Buffer.from(runtime); +const maskedTemplate = Buffer.from(runtimeTemplate); +for (const entries of Object.values(artifact.runtime_immutable_references || {})) { + for (const { start, length } of entries) { + maskedRuntime.fill(0, start, start + length); + maskedTemplate.fill(0, start, start + length); + } +} +if (!maskedRuntime.equals(maskedTemplate)) throw new Error('deployed runtime differs from build template'); + +const readContract = async (readProvider) => { + const contract = new Contract(expectedContract, artifact.abi, readProvider); + const callOptions = { blockTag: finalizedDeploymentBlockTag }; + const currentSetId = await contract.currentValidatorSetId(callOptions); + const readbackValidators = []; + for (const validator of validators) { + readbackValidators.push({ validator, enabled: await contract.validators(currentSetId, validator, callOptions) }); + } + return { + payment_token: getAddress(await contract.paymentToken(callOptions)), + governor: getAddress(await contract.governor(callOptions)), + paused: await contract.paused(callOptions), + decision_window_seconds: Number(await contract.decisionWindow(callOptions)), + current_validator_set_id: Number(currentSetId), + validator_threshold: Number(await contract.validatorThresholds(currentSetId, callOptions)), + validators: readbackValidators, + }; +}; +const [readback, verifyReadback, postDeploymentSafeReadback] = await Promise.all([ + readContract(provider), readContract(verifyProvider), verifySafeState(finalizedDeploymentBlockTag), +]); +if (canonicalJson(readback) !== canonicalJson(verifyReadback) + || canonicalJson(postDeploymentSafeReadback) !== canonicalJson(safeReadback) + || readback.payment_token !== BASE_USDC || readback.governor !== initialGovernor + || readback.paused || readback.decision_window_seconds !== decisionWindow + || readback.validator_threshold !== threshold || readback.validators.some(({ enabled }) => !enabled)) { + throw new Error('post-deployment constructor or Safe readback mismatch'); +} + +const receipt = { + ...plan, + schema: 'h1dr4.proofvault-deployment-receipt/v3', + status: 'confirmed_finalized', + contract: expectedContract, + transaction_hash: txReceipt.hash, + signed_transaction_sha256: sha256(hexToBuffer(signedTransaction, 'signed transaction')), + block_number: txReceipt.blockNumber, + block_hash: txReceipt.blockHash, + gas_used: txReceipt.gasUsed.toString(), + effective_gas_price_wei: txReceipt.gasPrice?.toString() || null, + actual_runtime_bytes: runtime.length, + actual_runtime_sha256: sha256(runtime), + immutable_masked_runtime_sha256: sha256(maskedRuntime), + immutable_masked_template_sha256: sha256(maskedTemplate), + independent_rpc_corroborated: true, + finalized_on_both_rpc_endpoints: true, + finality, + post_deployment_safe_readback: postDeploymentSafeReadback, + post_deployment_readback: readback, +}; +const receiptPath = path.join(receiptsDir, `proofvault-base-${txReceipt.hash}.json`); +fs.writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`, { mode: 0o600 }); +writeJournal('confirmed_finalized', { receipt_path: receiptPath }); +console.log(JSON.stringify({ ...receipt, receipt_path: receiptPath, journal_path: journalPath }, null, 2)); diff --git a/contracts-proofvault/test/evm.mjs b/contracts-proofvault/test/evm.mjs new file mode 100644 index 0000000..7c98f03 --- /dev/null +++ b/contracts-proofvault/test/evm.mjs @@ -0,0 +1,615 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import { spawnSync } from 'node:child_process'; + +import ganache from 'ganache'; +import solc from 'solc'; +import { + BrowserProvider, + ContractFactory, + keccak256, + parseUnits, + toUtf8Bytes, + ZeroAddress, +} from 'ethers'; + +const vaultPath = new URL('../H1DR4ProofVault.sol', import.meta.url); +const vaultSource = fs.readFileSync(vaultPath, 'utf8'); +const cryptoHelper = process.env.H1DR4_TEST_CRYPTO_HELPER; +function cryptoFixture(request) { + const result = spawnSync(process.env.H1DR4_TEST_PYTHON, [cryptoHelper], { + input: JSON.stringify(request), encoding: 'utf8', timeout: 30_000, + env: process.env, + }); + // Never print fixture stdin/stdout: it contains ephemeral test keys. + assert.equal(result.status, 0, 'synthetic crypto fixture failed'); + return JSON.parse(result.stdout); +} +const encryptedFixture = cryptoHelper ? cryptoFixture({ operation: 'make' }) : null; +async function assertEncryptedRoundtrip(submissionId) { + if (!encryptedFixture) return; + const submission = await vault.submissions(submissionId); + const result = cryptoFixture({ + operation: 'release', fixture: encryptedFixture, submission_id: submissionId, + observed: { + status: Number(submission.status), reward: Number(submission.reward), + release_completed: await vault.keyReleaseCompleted(submissionId), + ciphertext_hash: submission.reportCiphertextHash, + commitment: submission.reportCommitment, owner_key_hash: submission.ownerKeyHash, + }, + }); + assert.equal(result.roundtrip, true); + assert.equal(result.wrong_owner_rejected, true); + assert.equal(result.transport_contains_plaintext, false); +} +const tokenSource = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +contract MockUSDC { + string public constant name = "Mock USDC"; + string public constant symbol = "mUSDC"; + uint8 public constant decimals = 6; + uint16 public feeBps; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + function setFeeBps(uint16 nextFeeBps) external { + require(nextFeeBps <= 1_000); + feeBps = nextFeeBps; + } + + function mint(address to, uint256 amount) external { + balanceOf[to] += amount; + } + + function approve(address spender, uint256 amount) external returns (bool) { + allowance[msg.sender][spender] = amount; + return true; + } + + function transfer(address to, uint256 amount) external returns (bool) { + _move(msg.sender, to, amount); + return true; + } + + function transferFrom(address from, address to, uint256 amount) external returns (bool) { + uint256 allowed = allowance[from][msg.sender]; + require(allowed >= amount); + allowance[from][msg.sender] = allowed - amount; + _move(from, to, amount); + return true; + } + + function _move(address from, address to, uint256 amount) internal { + require(balanceOf[from] >= amount); + balanceOf[from] -= amount; + uint256 fee = amount * feeBps / 10_000; + balanceOf[to] += amount - fee; + } +} + +contract MockGovernor { + address public immutable owner; + + constructor(address initialOwner) { + require(initialOwner != address(0)); + owner = initialOwner; + } + + function execute(address target, bytes calldata data) external returns (bytes memory result) { + require(msg.sender == owner); + (bool ok, bytes memory returned) = target.call(data); + if (!ok) { + assembly { + revert(add(returned, 32), mload(returned)) + } + } + return returned; + } +} +`; + +function compile() { + const input = { + language: 'Solidity', + sources: { + 'H1DR4ProofVault.sol': { content: vaultSource }, + 'MockUSDC.sol': { content: tokenSource }, + }, + settings: { + evmVersion: 'paris', + viaIR: true, + optimizer: { enabled: true, runs: 200 }, + outputSelection: { '*': { '*': ['abi', 'evm.bytecode.object', 'evm.deployedBytecode.object'] } }, + }, + }; + const output = JSON.parse(solc.compile(JSON.stringify(input))); + const errors = (output.errors || []).filter((item) => item.severity === 'error'); + if (errors.length) throw new Error(errors.map((item) => item.formattedMessage).join('\n')); + return { + vault: output.contracts['H1DR4ProofVault.sol'].H1DR4ProofVault, + token: output.contracts['MockUSDC.sol'].MockUSDC, + governor: output.contracts['MockUSDC.sol'].MockGovernor, + }; +} + +async function expectRevert(promise, label) { + let reverted = false; + try { + const tx = await promise; + await tx.wait(); + } catch { + reverted = true; + } + assert.equal(reverted, true, `${label} should revert`); +} + +async function latestTimestamp(provider) { + // Avoid ethers' short-lived block cache after local evm_increaseTime/evm_mine. + return Number((await provider.send('eth_getBlockByNumber', ['latest', false])).timestamp); +} + +async function increaseTime(provider, seconds) { + await provider.send('evm_increaseTime', [seconds]); + await provider.send('evm_mine', []); +} + +const compiled = compile(); +const eip1193 = ganache.provider({ + chain: { chainId: 8453 }, + logging: { quiet: true }, + wallet: { totalAccounts: 8, defaultBalance: 1_000 }, +}); +// This local chain changes state immediately between revert and success tests. +const provider = new BrowserProvider(eip1193, undefined, { cacheTimeout: -1 }); +const [governor, owner, researcher, validatorA, validatorB, funder, outsider] = + await Promise.all(Array.from({ length: 7 }, (_, index) => provider.getSigner(index))); +const addresses = await Promise.all( + [governor, owner, researcher, validatorA, validatorB, funder, outsider].map((s) => s.getAddress()), +); +const [governorAddress, ownerAddress, researcherAddress, validatorAAddress, validatorBAddress, funderAddress, outsiderAddress] = addresses; + +const token = await new ContractFactory(compiled.token.abi, compiled.token.evm.bytecode.object, governor).deploy(); +await token.waitForDeployment(); +const governorContract = await new ContractFactory( + compiled.governor.abi, + compiled.governor.evm.bytecode.object, + governor, +).deploy(governorAddress); +await governorContract.waitForDeployment(); +const governorContractAddress = await governorContract.getAddress(); +const vaultFactory = new ContractFactory(compiled.vault.abi, compiled.vault.evm.bytecode.object, governor); + +await expectRevert( + vaultFactory.deploy( + outsiderAddress, + governorContractAddress, + [validatorAAddress, validatorBAddress], + 2, + 3_600, + ), + 'EOA payment token', +); +await expectRevert( + vaultFactory.deploy( + await token.getAddress(), + outsiderAddress, + [validatorAAddress, validatorBAddress], + 2, + 3_600, + ), + 'EOA initial governor', +); +await expectRevert( + vaultFactory.deploy( + await token.getAddress(), + governorContractAddress, + [validatorAAddress], + 1, + 3_600, + ), + 'single-validator governance', +); + +const vault = await vaultFactory.deploy( + await token.getAddress(), + governorContractAddress, + [validatorAAddress, validatorBAddress], + 2, + 3_600, +); +await vault.waitForDeployment(); +const vaultAddress = await vault.getAddress(); +const govCall = async (method, args = [], controller = governorContract) => { + const data = vault.interface.encodeFunctionData(method, args); + return controller.execute(vaultAddress, data); +}; +await expectRevert( + govCall('configureValidatorSet', [[validatorAAddress], 1]), + 'single-validator rotation', +); + +const unit = (value) => parseUnits(String(value), 6); +await (await token.mint(ownerAddress, unit(1_000))).wait(); +await (await token.mint(funderAddress, unit(1_000))).wait(); +await (await token.connect(owner).approve(vaultAddress, unit(1_000))).wait(); +await (await token.connect(funder).approve(vaultAddress, unit(1_000))).wait(); + +const targetHash = keccak256(toUtf8Bytes('https://authorized.example')); +const scopeHash = keccak256(toUtf8Bytes('web-and-api-v1')); +const ownerKey1 = keccak256(toUtf8Bytes('owner-key-v1')); +const ownerKey2 = encryptedFixture?.owner_key_hash ?? keccak256(toUtf8Bytes('owner-key-v2')); +await (await vault.connect(owner).registerEncryptionKey(ownerKey1)).wait(); +await (await govCall('authorizeTargetOwner', [targetHash, ownerAddress])).wait(); +assert.equal(await vault.targetOwners(targetHash), ownerAddress); +assert.equal(await vault.ownerKeyHashes(ownerAddress), ownerKey1); +await (await vault.connect(owner).createProgram( + targetHash, + scopeHash, + [unit(10), unit(20), unit(30), unit(40)], + 2, +)).wait(); +await expectRevert( + vault.connect(owner).createProgram( + keccak256(toUtf8Bytes('https://unverified.example')), + scopeHash, + [unit(10), unit(20), unit(30), unit(40)], + 2, + ), + 'unverified target owner', +); +await (await vault.connect(owner).fundProgram(1, unit(100))).wait(); + +const cipher1 = encryptedFixture?.reports['1'].report_ciphertext_hash ?? keccak256(toUtf8Bytes('ciphertext-1')); +const commitment1 = encryptedFixture?.reports['1'].report_commitment ?? keccak256(toUtf8Bytes('report-1')); +await expectRevert( + vault.connect(researcher).submitToProgram( + 1, + keccak256(toUtf8Bytes('unpermitted-cipher')), + keccak256(toUtf8Bytes('unpermitted-report')), + ), + 'unpermitted funded submission', +); +const permit1 = await vault.submissionPermitDigest(1, researcherAddress, cipher1, commitment1); +await (await govCall('authorizeSubmission', [permit1, (await latestTimestamp(provider)) + 1_000])).wait(); +await (await vault.connect(researcher).submitToProgram(1, cipher1, commitment1)).wait(); +let program = await vault.programs(1); +assert.equal(program.available, unit(60)); +assert.equal(program.locked, unit(40)); +assert.equal(program.openSubmissions, 1n); + +const replayCipher = keccak256(toUtf8Bytes('ciphertext-replay')); +const replayPermit = await vault.submissionPermitDigest(1, researcherAddress, replayCipher, commitment1); +await (await govCall('authorizeSubmission', [replayPermit, (await latestTimestamp(provider)) + 1_000])).wait(); +await expectRevert( + vault.connect(researcher).submitToProgram(1, replayCipher, commitment1), + 'duplicate report commitment', +); + +const verdict1 = keccak256(toUtf8Bytes('valid-high-1')); +await (await vault.connect(validatorA).attest(1, true, 2, verdict1)).wait(); +assert.equal((await vault.submissions(1)).status, 0n); +await (await vault.connect(validatorB).attest(1, true, 2, verdict1)).wait(); +program = await vault.programs(1); +assert.equal(program.available, unit(70)); +assert.equal(program.locked, unit(30)); +assert.equal(program.openSubmissions, 0n); +assert.equal((await vault.submissions(1)).status, 3n); + +await (await vault.connect(owner).registerEncryptionKey(ownerKey2)).wait(); +const researcherBefore = await token.balanceOf(researcherAddress); +const claimReceipt = await (await vault.connect(researcher).claimReward(1)).wait(); +assert.equal(await token.balanceOf(researcherAddress), researcherBefore + unit(30)); +const submission1 = await vault.submissions(1); +assert.equal(submission1.status, 4n); +assert.equal(submission1.ownerKeyHash, ownerKey2); +const releaseLog = claimReceipt.logs + .map((log) => { + try { return vault.interface.parseLog(log); } catch { return null; } + }) + .find((log) => log?.name === 'KeyReleaseAuthorized'); +assert.equal(releaseLog.args.ownerKeyHash, ownerKey2); +assert.equal(releaseLog.args.owner, ownerAddress); +await assertEncryptedRoundtrip(1); + +await expectRevert( + vault.connect(validatorA).attest(999, true, 1, verdict1), + 'nonexistent submission attestation', +); + +const cipher2 = keccak256(toUtf8Bytes('ciphertext-2')); +const commitment2 = keccak256(toUtf8Bytes('report-2')); +const permit2 = await vault.submissionPermitDigest(1, researcherAddress, cipher2, commitment2); +await (await govCall('authorizeSubmission', [permit2, (await latestTimestamp(provider)) + 1_000])).wait(); +await (await vault.connect(researcher).submitToProgram(1, cipher2, commitment2)).wait(); +const rejectedVerdict = keccak256(toUtf8Bytes('invalid-2')); +await (await vault.connect(validatorA).attest(2, false, 0, rejectedVerdict)).wait(); +await (await vault.connect(validatorB).attest(2, false, 0, rejectedVerdict)).wait(); +assert.equal((await vault.submissions(2)).status, 2n); +program = await vault.programs(1); +assert.equal(program.available, unit(70)); +assert.equal(program.locked, 0n); +assert.equal(program.openSubmissions, 0n); + +const cipher3 = keccak256(toUtf8Bytes('ciphertext-3')); +const commitment3 = keccak256(toUtf8Bytes('report-3')); +const permit3 = await vault.submissionPermitDigest(1, researcherAddress, cipher3, commitment3); +await (await govCall('authorizeSubmission', [permit3, (await latestTimestamp(provider)) + 1_000])).wait(); +await (await vault.connect(researcher).submitToProgram(1, cipher3, commitment3)).wait(); +await (await vault.connect(validatorA).attest(3, true, 2, keccak256(toUtf8Bytes('split-a')))).wait(); +await (await vault.connect(validatorB).attest(3, false, 0, keccak256(toUtf8Bytes('split-b')))).wait(); +await increaseTime(provider, 3_601); +await (await vault.connect(outsider).expireSubmission(3)).wait(); +assert.equal((await vault.submissions(3)).status, 5n); +program = await vault.programs(1); +assert.equal(program.available, unit(70)); +assert.equal(program.locked, 0n); +assert.equal(program.openSubmissions, 0n); + +await (await govCall('configureValidatorSet', [[validatorAAddress, validatorBAddress], 2])).wait(); +const privateDeadline = (await latestTimestamp(provider)) + 3_700; +const privateCipher = encryptedFixture?.reports['4'].report_ciphertext_hash ?? keccak256(toUtf8Bytes('private-cipher')); +const privateCommitment = encryptedFixture?.reports['4'].report_commitment ?? keccak256(toUtf8Bytes('private-report')); +await (await vault.connect(researcher).submitPrivate( + ownerAddress, + targetHash, + privateCipher, + privateCommitment, + privateDeadline, +)).wait(); +await (await vault.connect(funder).fundPrivateSubmission(4, unit(25))).wait(); +await expectRevert(vault.connect(researcher).claimReward(4), 'private payout before validation'); +assert.equal(await vault.keyReleaseCompleted(4), false); +const privateVerdict = keccak256(toUtf8Bytes('private-valid-medium')); +await (await vault.connect(validatorA).attest(4, true, 1, privateVerdict)).wait(); +await (await vault.connect(validatorB).attest(4, true, 1, privateVerdict)).wait(); +await expectRevert(vault.connect(researcher).claimReward(4), 'private payout before owner consent'); +await expectRevert(vault.connect(outsider).authorizePrivatePayout(4), 'unrelated owner consent'); +assert.equal(await vault.keyReleaseCompleted(4), false); +await (await vault.connect(owner).authorizePrivatePayout(4)).wait(); +const privateResearcherBefore = await token.balanceOf(researcherAddress); +const privateClaimReceipt = await (await vault.connect(researcher).claimReward(4)).wait(); +const privateReleaseLog = privateClaimReceipt.logs.map((log) => { + try { return vault.interface.parseLog(log); } catch { return null; } +}).find((log) => log?.name === 'KeyReleaseAuthorized'); +assert.equal(privateReleaseLog.args.ownerKeyHash, ownerKey2); +assert.equal(privateReleaseLog.args.owner, ownerAddress); +assert.equal(await token.balanceOf(researcherAddress), privateResearcherBefore + unit(25)); +assert.equal((await vault.submissions(4)).status, 4n); +assert.equal(await vault.privatePool(4), 0n); +await assertEncryptedRoundtrip(4); +await expectRevert(vault.connect(researcher).claimReward(4), 'duplicate private payout'); + +const refundDeadline = (await latestTimestamp(provider)) + 3_700; +await (await vault.connect(researcher).submitPrivate( + ownerAddress, + targetHash, + keccak256(toUtf8Bytes('refund-cipher')), + keccak256(toUtf8Bytes('refund-report')), + refundDeadline, +)).wait(); +await (await vault.connect(funder).fundPrivateSubmission(5, unit(10))).wait(); +const funderBeforeRefund = await token.balanceOf(funderAddress); +await increaseTime(provider, 3_701); +await (await vault.expireSubmission(5)).wait(); +await (await vault.connect(funder).refundPrivateContribution(5)).wait(); +assert.equal(await token.balanceOf(funderAddress), funderBeforeRefund + unit(10)); +assert.equal(await vault.privatePool(5), 0n); + +await (await token.setFeeBps(100)).wait(); +await expectRevert(vault.connect(owner).fundProgram(1, unit(10)), 'fee-on-transfer funding'); +assert.equal((await vault.programs(1)).available, unit(70)); +await (await token.setFeeBps(0)).wait(); + +const payoutCipher = keccak256(toUtf8Bytes('fee-payout-cipher')); +const payoutCommitment = keccak256(toUtf8Bytes('fee-payout-report')); +const payoutPermit = await vault.submissionPermitDigest( + 1, + researcherAddress, + payoutCipher, + payoutCommitment, +); +await (await govCall('authorizeSubmission', [payoutPermit, (await latestTimestamp(provider)) + 1_000])).wait(); +await (await vault.connect(researcher).submitToProgram(1, payoutCipher, payoutCommitment)).wait(); +const payoutVerdict = keccak256(toUtf8Bytes('fee-payout-valid-low')); +await (await vault.connect(validatorA).attest(6, true, 0, payoutVerdict)).wait(); +await (await vault.connect(validatorB).attest(6, true, 0, payoutVerdict)).wait(); +await (await token.setFeeBps(100)).wait(); +await expectRevert(vault.connect(researcher).claimReward(6), 'fee-on-transfer payout'); +assert.equal((await vault.submissions(6)).status, 3n); +assert.equal((await vault.programs(1)).locked, unit(10)); +await (await token.setFeeBps(0)).wait(); +await expectRevert( + vault.connect(outsider).claimRewardTo(6, outsiderAddress), + 'nonresearcher payout redirect', +); +const outsiderBeforeRedirect = await token.balanceOf(outsiderAddress); +const routedClaimReceipt = await ( + await vault.connect(researcher).claimRewardTo(6, outsiderAddress, { gasLimit: 1_000_000 }) +).wait(); +assert.equal(await token.balanceOf(outsiderAddress), outsiderBeforeRedirect + unit(10)); +assert.equal((await vault.submissions(6)).status, 4n); +assert.equal((await vault.programs(1)).locked, 0n); +const routedRewardEvent = routedClaimReceipt.logs.map((log) => { + try { return vault.interface.parseLog(log); } catch { return null; } +}).find((log) => log?.name === 'RewardPaid'); +assert.equal(routedRewardEvent.args.researcher, researcherAddress); +assert.equal(routedRewardEvent.args.recipient, outsiderAddress); + +const disabledCipher = keccak256(toUtf8Bytes('disabled-set-cipher')); +const disabledCommitment = keccak256(toUtf8Bytes('disabled-set-report')); +const disabledPermit = await vault.submissionPermitDigest( + 1, + researcherAddress, + disabledCipher, + disabledCommitment, +); +await (await govCall('authorizeSubmission', [disabledPermit, (await latestTimestamp(provider)) + 1_000])).wait(); +await (await vault.connect(researcher).submitToProgram(1, disabledCipher, disabledCommitment)).wait(); +await (await govCall('disableValidatorSet', [2])).wait(); +await expectRevert( + vault.connect(validatorA).attest(7, true, 1, keccak256(toUtf8Bytes('disabled-verdict'))), + 'disabled validator set', +); +await (await govCall('configureValidatorSet', [[validatorAAddress, validatorBAddress], 2])).wait(); +await increaseTime(provider, 3_601); +await (await vault.expireSubmission(7)).wait(); +assert.equal((await vault.submissions(7)).status, 5n); +assert.equal((await vault.programs(1)).locked, 0n); + +await (await govCall('setPaused', [true])).wait(); +await expectRevert(vault.connect(owner).fundProgram(1, unit(1)), 'paused funding'); +await (await govCall('setPaused', [false])).wait(); + +const cancelledCipher = keccak256(toUtf8Bytes('cancelled-cipher')); +const cancelledCommitment = keccak256(toUtf8Bytes('cancelled-report')); +const cancelledPermit = await vault.submissionPermitDigest( + 1, + researcherAddress, + cancelledCipher, + cancelledCommitment, +); +await (await govCall('authorizeSubmission', [cancelledPermit, (await latestTimestamp(provider)) + 1_000])).wait(); +await (await govCall('cancelSubmissionAuthorization', [cancelledPermit])).wait(); +assert.equal(await vault.submissionPermits(cancelledPermit), 0n); +await expectRevert( + vault.connect(researcher).submitToProgram(1, cancelledCipher, cancelledCommitment), + 'cancelled submission permit', +); + +const revocationPaidCipher = keccak256(toUtf8Bytes('revocation-paid-cipher')); +const revocationPaidCommitment = keccak256(toUtf8Bytes('revocation-paid-report')); +const revocationPaidPermit = await vault.submissionPermitDigest( + 1, + researcherAddress, + revocationPaidCipher, + revocationPaidCommitment, +); +await (await govCall('authorizeSubmission', [ + revocationPaidPermit, + (await latestTimestamp(provider)) + 1_000, +])).wait(); +await (await vault.connect(researcher).submitToProgram( + 1, + revocationPaidCipher, + revocationPaidCommitment, +)).wait(); +const revocationPaidVerdict = keccak256(toUtf8Bytes('revocation-paid-valid-low')); +await (await vault.connect(validatorA).attest(8, true, 0, revocationPaidVerdict)).wait(); +await (await vault.connect(validatorB).attest(8, true, 0, revocationPaidVerdict)).wait(); +assert.equal((await vault.submissions(8)).status, 3n); + +const revokedCommittedCipher = keccak256(toUtf8Bytes('revoked-committed-cipher')); +const revokedCommittedCommitment = keccak256(toUtf8Bytes('revoked-committed-report')); +const revokedCommittedPermit = await vault.submissionPermitDigest( + 1, + researcherAddress, + revokedCommittedCipher, + revokedCommittedCommitment, +); +await (await govCall('authorizeSubmission', [ + revokedCommittedPermit, + (await latestTimestamp(provider)) + 1_000, +])).wait(); +await (await vault.connect(researcher).submitToProgram( + 1, + revokedCommittedCipher, + revokedCommittedCommitment, +)).wait(); + +const staleCipher = keccak256(toUtf8Bytes('stale-permit-cipher')); +const staleCommitment = keccak256(toUtf8Bytes('stale-permit-report')); +const stalePermit = await vault.submissionPermitDigest( + 1, + researcherAddress, + staleCipher, + staleCommitment, +); +await (await govCall('authorizeSubmission', [stalePermit, (await latestTimestamp(provider)) + 1_000])).wait(); + +await (await govCall('revokeTargetOwner', [targetHash])).wait(); +assert.equal(await vault.targetOwners(targetHash), ZeroAddress); +await expectRevert(vault.connect(owner).fundProgram(1, unit(1)), 'revoked program funding'); +await expectRevert( + vault.connect(researcher).submitToProgram(1, staleCipher, staleCommitment), + 'stale permit after target revocation', +); +await expectRevert( + vault.connect(validatorA).attest( + 9, + true, + 0, + keccak256(toUtf8Bytes('revoked-committed-verdict')), + ), + 'attestation after target revocation', +); + +const deferredClaim = await (await vault.connect(researcher).claimReward(8)).wait(); +const deferredEvents = deferredClaim.logs.map((log) => { + try { return vault.interface.parseLog(log); } catch { return null; } +}).filter(Boolean); +assert.equal(deferredEvents.some((log) => log.name === 'KeyReleaseAuthorized'), false); +assert.equal(deferredEvents.some((log) => log.name === 'KeyReleaseDeferred'), true); +assert.equal(await vault.keyReleaseCompleted(8), false); + +const newOwnerKey = keccak256(toUtf8Bytes('replacement-owner-key')); +await (await vault.connect(outsider).registerEncryptionKey(newOwnerKey)).wait(); +await (await govCall('authorizeTargetOwner', [targetHash, outsiderAddress])).wait(); +const rebindReceipt = await (await govCall('rebindFundedReportOwner', [8])).wait(); +const rebindEvents = rebindReceipt.logs.map((log) => { + try { return vault.interface.parseLog(log); } catch { return null; } +}).filter(Boolean); +const reboundRelease = rebindEvents.find((log) => log.name === 'KeyReleaseAuthorized'); +assert.equal(reboundRelease.args.owner, outsiderAddress); +assert.equal(reboundRelease.args.ownerKeyHash, newOwnerKey); +assert.equal(await vault.keyReleaseCompleted(8), true); +await expectRevert(govCall('rebindFundedReportOwner', [8]), 'duplicate report-key release'); + +await increaseTime(provider, 3_601); +await (await vault.expireSubmission(9)).wait(); +assert.equal((await vault.submissions(9)).status, 5n); + +assert.equal(await vault.governor(), governorContractAddress); +assert.equal(vault.interface.hasFunction('beginGovernanceTransfer'), false); +await (await govCall('setPaused', [true])).wait(); +await (await govCall('setPaused', [false])).wait(); + +assert.notEqual(await token.getAddress(), ZeroAddress); +assert.ok(compiled.vault.evm.deployedBytecode.object.length / 2 < 24_576); + +const result = { + chain_id: 8453, + contract_source_sha256: (await import('node:crypto')).createHash('sha256').update(vaultSource).digest('hex'), + creation_bytecode_bytes: compiled.vault.evm.bytecode.object.length / 2, + runtime_bytecode_bytes: compiled.vault.evm.deployedBytecode.object.length / 2, + checks: { + private_payout_requires_validation_and_owner_consent: true, + duplicate_private_payout_rejected: true, + exact_funded_payment_and_rotated_key_release: true, + exact_private_pool_payment: true, + expired_private_refund: true, + unverified_target_rejected: true, + unpermitted_and_duplicate_submission_rejected: true, + split_quorum_expiry_recovery: true, + nonexistent_submission_vote_rejected: true, + fee_token_credit_rejected: true, + fee_token_payout_and_release_rejected: true, + disabled_validator_set_expires_safely: true, + emergency_pause_blocks_new_value: true, + cancelled_permit_rejected: true, + target_revocation_blocks_funding_submission_and_attestation: true, + revoked_owner_claim_pays_but_defers_key_release: true, + report_rebound_to_current_owner_and_released_once: true, + immutable_contract_wallet_governor_from_block_zero: true, + validator_threshold_minimum_enforced_on_chain: true, + researcher_directed_payout_recipient: true, + }, + encrypted_fixture_integration: encryptedFixture ? { + funded_report_roundtrip_after_local_evm_payout: true, + private_report_roundtrip_after_local_evm_payout: true, + wrong_owner_rejected: true, + scope: 'Local EVM and mock USDC only; not a production key-release service', + } : null, +}; +console.log(JSON.stringify(result, null, 2)); diff --git a/dashboard/app/architecture.tsx b/dashboard/app/architecture.tsx new file mode 100644 index 0000000..5fc7b13 --- /dev/null +++ b/dashboard/app/architecture.tsx @@ -0,0 +1,389 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; +import type { IdentitySnapshot, Snapshot } from './model'; + +type RuntimeMode = 'local' | 'cloud'; +type ComponentId = 'operator' | 'virtuals' | 'agent' | 'attackgraph' | 'policy' | 'h1dr4' | 'sibyl' | 'execution' | 'base' | 'dashboard'; +type NodePort = 'top' | 'right' | 'bottom' | 'left'; +type DocChapterId = 'model' | 'request' | 'ownership' | 'runtime' | 'proof'; + +type ComponentSpec = { + id: ComponentId; + eyebrow: string; + title: string; + role: string; + stores: string; + boundary: string; + tone: 'pink' | 'aqua' | 'purple' | 'orange' | 'green' | 'muted'; +}; + +const COMPONENTS: Record = { + operator: { + id: 'operator', eyebrow: 'AUTHORITY', title: 'OPERATOR + TEAM', tone: 'pink', + role: 'Creates the engagement, defines exact scope, invites humans, and issues revocable identities to agent workers.', + stores: 'Passkeys, memberships and browser sessions live in the local control database.', + boundary: 'Humans operate the dashboard. Agents do the work through scoped MCP identities.', + }, + virtuals: { + id: 'virtuals', eyebrow: 'OPTIONAL ADAPTER', title: 'VIRTUALS / ACP', tone: 'muted', + role: 'A future distribution and agent-commerce adapter. A Virtuals agent would enter as an ordinary scoped MCP worker.', + stores: 'No AttackGraph memory, findings or target data belong in Virtuals.', + boundary: 'Not present in v1. Removing it changes nothing in the core product.', + }, + agent: { + id: 'agent', eyebrow: 'REASONING PLANE', title: 'ANY MCP AGENT', tone: 'aqua', + role: 'Codex, Hermes, Claude, a local model, or another MCP host reads the brief, plans work and reports semantic telemetry.', + stores: 'The model context is temporary. Durable engagement state belongs to Sibyl.', + boundary: 'The agent can assert findings, but it cannot self-declare executor proof or a PWNED state.', + }, + attackgraph: { + id: 'attackgraph', eyebrow: 'CONTROL PLANE', title: 'H1DR4 ATTACKGRAPH MCP', tone: 'pink', + role: 'The model-agnostic broker that exposes scope, memory, telemetry, policy, execution and evidence tools.', + stores: 'No independent engagement database: it reads and writes through Sibyl and the identity control store.', + boundary: 'Every target is checked against the engagement allowlist before telemetry or execution is accepted.', + }, + policy: { + id: 'policy', eyebrow: 'TRUST GATE', title: 'SCOPE + POLICY', tone: 'orange', + role: 'Evaluates target, lane, risk, destructive patterns, runtime and budget before an active action becomes dispatchable.', + stores: 'The decision and proposed action become part of the engagement graph.', + boundary: 'A staged action is not evidence. It cannot change posture until an executor result is correlated.', + }, + h1dr4: { + id: 'h1dr4', eyebrow: 'CAPABILITY PLANE', title: 'H1DR4 TOOLS', tone: 'purple', + role: 'Supplies discoverable OSINT, security and infrastructure capabilities without coupling AttackGraph to a fixed tool catalog.', + stores: 'Capability descriptions are discovered on demand; engagement truth remains in Sibyl.', + boundary: 'H1DR4 expands what workers can do. It is not the memory or the execution machine.', + }, + sibyl: { + id: 'sibyl', eyebrow: 'MEMORY PLANE', title: 'SIBYL MEMORY', tone: 'green', + role: 'The shared operational brain: hot graph, cold event history, findings, failed paths, loot, proof and regressions.', + stores: 'Local default: .attackgraph/sibyl.db, isolated by deterministic operator tenant.', + boundary: 'Secrets are redacted before persistence. Removing Sibyl destroys fresh-session recall and coordinated state.', + }, + execution: { + id: 'execution', eyebrow: 'EXECUTION PLANE', title: 'EXECUTION RUNTIME', tone: 'purple', + role: 'Runs the bounded command or job selected by the operator and agent.', + stores: 'Transient command state and output until normalized telemetry is returned to AttackGraph.', + boundary: 'Execution is replaceable: use the operator machine locally or disposable H3RETIK infrastructure.', + }, + base: { + id: 'base', eyebrow: 'SETTLEMENT PLANE', title: 'BASE / USDC', tone: 'orange', + role: 'Settles H3RETIK compute receipts and unlocks or extends a paid disposable session.', + stores: 'Payment transaction state only. No targets, findings, credentials, prompts or attack graph.', + boundary: 'Base is required for paid H3RETIK compute, not for local execution or Sibyl memory.', + }, + dashboard: { + id: 'dashboard', eyebrow: 'OPERATOR VIEW', title: 'ATTACKGRAPH DASHBOARD', tone: 'pink', + role: 'Projects Sibyl into the operation brief, target building, live feed, worker roster, attacks, loot and verified posture.', + stores: 'The browser keeps only device-local view preferences and an authenticated browser session.', + boundary: 'The dashboard displays state. It is not the system of record and does not execute attacks.', + }, +}; + +const FLOW = [ + { id: 'connect', label: 'CONNECT', component: 'operator' as ComponentId, title: 'Create the authorized workspace', input: 'Target + scope + mode + lanes', output: 'Engagement ID + agent memberships', guard: 'An agent identity can access only engagements where it has membership.' }, + { id: 'recall', label: 'RECALL', component: 'sibyl' as ComponentId, title: 'Load the shared operational brain', input: 'attackgraph_get_brief', output: 'Confirmed evidence + hypotheses + exhausted paths + pending work', guard: 'A fresh model session receives durable state without replaying the old conversation.' }, + { id: 'plan', label: 'PLAN', component: 'policy' as ComponentId, title: 'Convert reasoning into a scoped action', input: 'Target + lane + command + risk + budget', output: 'Recorded action + policy decision', guard: 'A planned or queued job is never treated as successful evidence.' }, + { id: 'execute', label: 'EXECUTE', component: 'execution' as ComponentId, title: 'Run in the selected execution plane', input: 'Approved action specification', output: 'Status + exit code + sanitized output', guard: 'Local and cloud execution are interchangeable; the engagement memory is not.' }, + { id: 'report', label: 'REPORT', component: 'attackgraph' as ComponentId, title: 'Normalize activity into telemetry v1', input: 'Event type + meaning + entities + relationships', output: 'Asserted semantic event in Sibyl', guard: 'The model supplies meaning, not proof authority.' }, + { id: 'promote', label: 'PROMOTE', component: 'sibyl' as ComponentId, title: 'Correlate evidence without duplicating it', input: 'Same idempotency key + executor attestation', output: 'ASSERTED → ATTESTED → VERIFIED', guard: 'Verified requires authenticated executor evidence tied to the scoped action and target.' }, + { id: 'render', label: 'RENDER', component: 'dashboard' as ComponentId, title: 'Project memory into operator state', input: 'Sibyl graph + journal + proof chain', output: 'Rooms + live feed + loot + WHY THIS STATE', guard: 'Free-form labels cannot set PWNED; posture is derived from qualifying evidence.' }, +]; + +const HIERARCHY = [ + { level: 0, label: 'OPERATOR TENANT', meta: 'ISOLATION BOUNDARY', tone: 'pink' }, + { level: 1, label: 'ENGAGEMENT', meta: 'TARGET + SCOPE + MODE', tone: 'aqua' }, + { level: 2, label: 'IDENTITY CONTROL', meta: 'PASSKEYS / AGENTS / MEMBERSHIPS', tone: 'purple' }, + { level: 2, label: 'H3RETIK SESSION BINDINGS', meta: 'COMPUTE LENSES, NOT THE TARGET', tone: 'purple' }, + { level: 2, label: 'SIBYL GRAPH', meta: 'DURABLE SHARED BRAIN', tone: 'green' }, + { level: 3, label: 'TELEMETRY EVENT', meta: 'ACTOR + TARGET + OUTCOME', tone: 'green' }, + { level: 4, label: 'ENTITIES + RELATIONSHIPS', meta: 'WHAT CONNECTS TO WHAT', tone: 'aqua' }, + { level: 4, label: 'PROOF + ASSURANCE', meta: 'ASSERTED / ATTESTED / VERIFIED', tone: 'orange' }, + { level: 3, label: 'MATERIALIZED RECORDS', meta: 'FINDINGS / ATTEMPTS / LOOT / CHECKPOINTS', tone: 'pink' }, + { level: 3, label: 'JOURNAL EVENTS', meta: 'REAL-TIME FEED + FRESH RECALL', tone: 'purple' }, +]; + +const COMPARISON = [ + ['EXECUTION', 'Operator machine or local container', 'Disposable scoped H3RETIK machine'], + ['MEMORY', 'Same local Sibyl engagement', 'Same local Sibyl engagement'], + ['ISOLATION', 'Depends on operator environment', 'Ephemeral compute boundary'], + ['PAYMENT', 'None', 'Receipt settled on Base in USDC/H1DR4'], + ['TOOLS', 'Anything installed locally', 'Lean image + tools loaded for the session'], + ['PROOF', 'Agent assertion unless a trusted runner attests', 'Session/job/command evidence can be attested'], + ['CLEANUP', 'Operator responsibility', 'Runtime expires and is destroyed'], + ['BEST FOR', 'Fast trusted labs and development', 'Risky tooling, clean demos and parallel workers'], +]; + +const DOC_CHAPTERS: Array<{ + id: DocChapterId; + nav: string; + title: string; + lead: string; + invariant: string; + points: Array<{ label: string; title: string; body: string }>; +}> = [ + { + id: 'model', nav: 'MENTAL MODEL', title: 'Five parts, one engagement.', + lead: 'AttackGraph is the control surface around an authorized red-team engagement. Agents may come and go; the engagement identity and Sibyl memory remain.', + invariant: 'The target is the engagement. An H3RETIK machine is only a temporary worker attached to it.', + points: [ + { label: 'AUTHORITY', title: 'Operator + team', body: 'Create scope, invite people and issue revocable identities to agent workers.' }, + { label: 'CONTROL', title: 'AttackGraph MCP', body: 'Checks identity and scope, exposes tools, records actions and routes bounded execution.' }, + { label: 'MEMORY', title: 'Sibyl', body: 'Keeps the durable graph, event history, findings, failed paths, loot and proof across fresh agents.' }, + { label: 'COMPUTE', title: 'Local or H3RETIK', body: 'Runs the job. It can be replaced without replacing the engagement or its memory.' }, + ], + }, + { + id: 'request', nav: 'REQUEST PATH', title: 'What happens when an agent acts.', + lead: 'A command is never sent straight from a model to a machine. It moves through a typed, scoped path and returns as normalized evidence.', + invariant: 'Planning, execution and proof are distinct events. A requested action is never evidence of success.', + points: [ + { label: '01 / RECALL', title: 'Read the brief', body: 'The agent loads confirmed facts, hypotheses, failed attempts and pending work from Sibyl.' }, + { label: '02 / AUTHORIZE', title: 'Check the action', body: 'AttackGraph binds the proposed command to agent identity, engagement scope, lane and budget.' }, + { label: '03 / EXECUTE', title: 'Run one bounded job', body: 'The selected local or H3RETIK runtime produces status, output and executor metadata.' }, + { label: '04 / INGEST', title: 'Normalize the result', body: 'AttackGraph redacts the return, correlates proof, writes Sibyl and projects the new state to the dashboard.' }, + ], + }, + { + id: 'ownership', nav: 'DATA OWNERSHIP', title: 'Every datum has one proper home.', + lead: 'The system avoids a second hidden source of truth. Durable operational truth belongs to Sibyl; short-lived execution state stays with the runtime.', + invariant: 'Targets, prompts, findings, credentials and attack history never belong on Base or inside Virtuals.', + points: [ + { label: 'IDENTITY STORE', title: 'Who may enter', body: 'Passkeys, team membership, agent credentials and revocation state.' }, + { label: 'SIBYL', title: 'What the operation knows', body: 'Redacted telemetry, entities, relationships, attempts, proof, provenance and derived posture.' }, + { label: 'RUNTIME', title: 'What the current job needs', body: 'Transient process state, command output and artifacts until their safe result is ingested.' }, + { label: 'BASE', title: 'What cloud compute cost', body: 'Payment and receipt state only. It unlocks compute but never stores attack data.' }, + ], + }, + { + id: 'runtime', nav: 'LOCAL VS CLOUD', title: 'Same brain, different execution boundary.', + lead: 'Changing the execution lens does not create a different product. The MCP contract, engagement ID, Sibyl records and operator view remain the same.', + invariant: 'H3RETIK improves isolation, disposability and executor evidence; it does not replace Sibyl or the dashboard.', + points: [ + { label: 'LOCAL', title: 'Fast trusted work', body: 'Use the operator machine or a local container. No payment rail; cleanup is the operator’s responsibility.' }, + { label: 'H3RETIK', title: 'Disposable scoped compute', body: 'Rent a short-lived machine, load the needed tool profile, run the bounded job and destroy the runtime.' }, + { label: 'SETTLEMENT', title: 'Base unlocks the session', body: 'A USDC receipt authorizes paid remote capacity. No engagement memory is written onchain.' }, + { label: 'RETURN', title: 'Evidence rejoins the graph', body: 'Sanitized job facts flow back through AttackGraph into the same Sibyl engagement.' }, + ], + }, + { + id: 'proof', nav: 'EVIDENCE + STATE', title: 'How a report becomes trusted posture.', + lead: 'Agents provide semantic meaning, but high-impact dashboard state is derived only after that meaning correlates with authenticated executor evidence.', + invariant: 'An agent cannot write PWNED directly. The dashboard derives state from qualifying, traceable Sibyl records.', + points: [ + { label: 'ASSERTED', title: 'The agent reports meaning', body: 'Useful for coordination and hypotheses, but insufficient for a high-impact state change.' }, + { label: 'ATTESTED', title: 'Executor facts exist', body: 'Authenticated runtime output is present, but full action and target correlation is incomplete.' }, + { label: 'VERIFIED', title: 'Proof is correlated', body: 'Target, scoped action, session, outcome and proof reference agree under one idempotency key.' }, + { label: 'DERIVED', title: 'The dashboard explains why', body: 'Posture is computed deterministically and links back through WHY THIS STATE to supporting records.' }, + ], + }, +]; + +export default function ArchitectureView({ snapshot, identity }: { snapshot: Snapshot; identity: IdentitySnapshot }) { + const [mode, setMode] = useState('cloud'); + const [selected, setSelected] = useState('attackgraph'); + const [step, setStep] = useState(0); + const [running, setRunning] = useState(false); + const [chapter, setChapter] = useState('model'); + + useEffect(() => { + if (!running) return; + const timer = window.setInterval(() => setStep((current) => (current + 1) % FLOW.length), 1250); + return () => window.clearInterval(timer); + }, [running]); + + const execution = useMemo(() => mode === 'cloud' ? { + ...COMPONENTS.execution, + title: 'H3RETIK CLOUD SESSION', + role: 'Agent-native command compute: a paid, disposable, scoped machine rented by action quota or short compute window.', + stores: 'Transient commands, logs and artifacts until sanitized results are ingested into Sibyl.', + boundary: 'The session is execution capacity, not an engagement and not the long-term memory.', + } : { + ...COMPONENTS.execution, + title: 'LOCAL RUNNER', + role: 'Runs authorized work on the operator workstation, local Kali container, or another trusted local sandbox.', + stores: 'Local process and filesystem state. AttackGraph still records normalized results in Sibyl.', + boundary: 'No Base payment and no cloud isolation. Cleanup and tool hygiene remain operator responsibilities.', + }, [mode]); + const selectedSpec = selected === 'execution' ? execution : COMPONENTS[selected]; + const activeFlow = FLOW[step]; + const activeChapter = DOC_CHAPTERS.find((item) => item.id === chapter) ?? DOC_CHAPTERS[0]; + const liveWorkers = identity.agents.filter((agent) => agent.status === 'active').length; + + const choose = (id: ComponentId) => { + setSelected(id); + const matchingStep = FLOW.findIndex((item) => item.component === id); + if (matchingStep >= 0) setStep(matchingStep); + }; + + return
+
+
+ 06 / INTERACTIVE SYSTEM MANUAL +

One brain. Replaceable workers.

+

Click any system block or run the lifecycle to inspect ownership, data flow and trust boundaries.

+
+
+ EXECUTION LENS +
+ + +
+
+
+ +
+
SIBYLLIVE{snapshot.memory.event_count} JOURNAL EVENTS
+
GRAPH{snapshot.stats.nodes}{snapshot.stats.relationships || 0} RELATIONSHIPS
+
WORKERS{liveWorkers}{identity.agents.length} REGISTERED
+
H3 SESSIONS{identity.h3retik_sessions.length}BOUND TO ENGAGEMENT
+
RUNTIME{mode === 'cloud' ? 'REMOTE' : 'LOCAL'}{mode === 'cloud' ? 'BASE-SETTLED' : 'NO PAYMENT RAIL'}
+
+ +
+
+
COREREPLACEABLEOPTIONAL
+ +
+
01ENTRY / WHO CAN PARTICIPATE
+
+ choose('operator')} /> + + choose('agent')} /> + + choose('virtuals')} /> +
+
+ + + +
+
02ORCHESTRATION / ONE GOVERNING CONTROL PLANE
+
+ choose('policy')} /> + + choose('attackgraph')} /> + + choose('h1dr4')} /> +
+
+ + + +
+
03OPERATION / DURABLE BRAIN + REPLACEABLE RUNTIME
+
+ choose('sibyl')} /> +
NO DIRECT MEMORY WRITE
+ choose('execution')} /> +
+
+ + + +
+
04OUTPUT / WHAT HUMANS SEE + WHAT CLOUD COMPUTE COSTS
+
+ choose('dashboard')} /> +
NO ATTACK DATA ONCHAIN
+ choose('base')} /> +
+
+
+ + +
+ +
+ +
+
+ CHAPTER {String(DOC_CHAPTERS.indexOf(activeChapter) + 1).padStart(2, '0')} / {activeChapter.nav} +

{activeChapter.title}

+

{activeChapter.lead}

+
+
+ {activeChapter.points.map((point, index) =>
{String(index + 1).padStart(2, '0')}
{point.label}

{point.title}

{point.body}

)} +
+
NON-NEGOTIABLE{activeChapter.invariant}
+
+
+ +
+
+
ATTACK LIFECYCLE

Follow one action through the stack

+ +
+
+ {FLOW.map((item, index) => )} +
+
+
{String(step + 1).padStart(2, '0')}/ {String(FLOW.length).padStart(2, '0')}
+
{activeFlow.label}::{COMPONENTS[activeFlow.component].eyebrow}

{activeFlow.title}

{activeFlow.guard}

+
INPUT
{activeFlow.input}
OUTPUT
{activeFlow.output}
+
+
+ +
+
+
DATA HIERARCHYWHO OWNS WHAT
+
{HIERARCHY.map((item, index) =>
{item.label}{item.meta}
)}
+
+ +
+
ASSURANCE LADDERHOW PWNED BECOMES TRUE
+
01
ASSERTED

An agent reports semantic meaning. Useful for coordination, never enough for high-impact posture.

+
SAME IDEMPOTENCY KEY + EXECUTOR EVIDENCE ↓
+
02
ATTESTED

Authenticated executor facts exist, but no scoped AttackGraph action correlation is complete.

+
TARGET + ACTION + SESSION + SUCCESS CORRELATE ↓
+
03
VERIFIED

Proof is bound to the authorized action. Sibyl may now promote the same record and posture.

+
+
+ +
+
RUNTIME COMPARISON

Same brain, different execution boundary

{mode === 'cloud' ? 'H3RETIK LENS ACTIVE' : 'LOCAL LENS ACTIVE'}
+
+
LAYERLOCALH3RETIK CLOUD
+ {COMPARISON.map(([label, local, cloud]) =>
{label}{local}{cloud}
)} +
+
+ +
+
DEPENDENCY TEST

What actually breaks if a layer disappears?

+
+
REMOVE SIBYLTHE PRODUCT BREAKS

Fresh agents forget evidence and failed paths. Shared graph, provenance and durable posture disappear.

+
REMOVE H3RETIKLOCAL MODE STILL WORKS

You lose disposable cloud isolation and proof-rich remote jobs, not the MCP brain or dashboard.

+
REMOVE BASECLOUD RENTAL STOPS

Paid H3RETIK sessions cannot unlock. Local execution and all existing Sibyl memory remain usable.

+
REMOVE VIRTUALSNOTHING CORE CHANGES

Virtuals may distribute the service later. It is not execution, memory, identity or evidence authority.

+
+
+ +
CORE DOCTRINEH3RETIK COMPUTES. SIBYL REMEMBERS. ATTACKGRAPH GOVERNS. THE AGENT REASONS.Base settles remote compute. Virtuals remains an optional market adapter.
+
; +} + +function SystemNode({ spec, selected, ports = [], featured = false, optional = false, inactive = false, onClick }: { spec: ComponentSpec; selected: boolean; ports?: NodePort[]; featured?: boolean; optional?: boolean; inactive?: boolean; onClick: () => void }) { + return