From be5fece3f0653fe7734fb0b2253b4bc735a3bf15 Mon Sep 17 00:00:00 2001 From: ali Date: Thu, 19 Feb 2026 03:28:00 +0330 Subject: [PATCH 01/14] feat: enhance deployment and upgrade scripts for DonationHandler - Updated `deploy:sepolia` script to deploy the DonationHandler implementation. - Added new upgrade scripts for both mainnet and sepolia, including a test fork option. - Expanded README with detailed instructions on upgrading existing deployments and verifying upgrades. - Improved logging in the deployment script for better visibility of deployment details. --- README.md | 79 +++++++ TESTNET_DEPLOYMENT.md | 339 ++++++++++++++++++++++++++++ package.json | 5 +- script/DeployDonationHandler.s.sol | 37 ++- script/TestUpgrade.s.sol | 98 ++++++++ script/UpgradeDonationHandler.s.sol | 86 +++++++ 6 files changed, 634 insertions(+), 10 deletions(-) create mode 100644 TESTNET_DEPLOYMENT.md create mode 100644 script/TestUpgrade.s.sol create mode 100644 script/UpgradeDonationHandler.s.sol diff --git a/README.md b/README.md index 0eda669..40360b3 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,85 @@ The deployments are stored in ./broadcast See the [Foundry Book for available options](https://book.getfoundry.sh/reference/forge/forge-create.html). + +## Upgrading Existing Deployments + +The DonationHandler uses **TransparentUpgradeableProxy**, allowing you to upgrade the implementation without deploying a new proxy. Users continue using the same address. + +### 🎯 Quick Upgrade (Ethereum Mainnet) + +```bash +# 1. Set up environment variables +export PRIVATE_KEY="your_private_key" +export PROXY_ADDRESS="0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676" +export PROXY_ADMIN_ADDRESS="0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409" +export MAINNET_RPC="your_rpc_url" + +# 2. Test on fork first (SAFE - no real transactions) +yarn upgrade:mainnet:fork + +# 3. If tests pass, upgrade on mainnet +yarn upgrade:mainnet +``` + +### πŸ“‹ Deployed Addresses + +#### Ethereum Mainnet (Chain ID: 1) +- **Proxy**: `0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676` (users interact with this) +- **ProxyAdmin**: `0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409` (controls upgrades) + +For other networks (Optimism, Gnosis, Polygon, Base, Celo), check your `broadcast/` folder. + +### πŸ”§ Available Upgrade Scripts + +```bash +# Upgrade on mainnet (requires PROXY_ADDRESS env var) +yarn upgrade:mainnet + +# Test upgrade on fork before mainnet (recommended!) +yarn upgrade:mainnet:fork +``` + +### πŸ“ Manual Upgrade Process + +If you prefer manual control: + +```bash +# Deploy new implementation and upgrade proxy +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $MAINNET_RPC \ + --broadcast \ + --verify \ + -vvvv +``` + +### βœ… Verify Upgrade + +After upgrading, verify the new implementation: + +```bash +# Check current implementation address +cast call $PROXY_ADDRESS "implementation()(address)" --rpc-url $MAINNET_RPC +``` + +### ⚠️ Important Notes + +- **Test on fork first** - Always run `yarn upgrade:mainnet:fork` before mainnet +- **ProxyAdmin owner** - Ensure your account owns the ProxyAdmin contract +- **Gas costs** - Expect ~1.45M gas (~0.05-0.1 ETH depending on gas prices) +- **State preserved** - All existing data remains intact after upgrade +- **Same address** - Users continue using the same proxy address + +### πŸ”„ What the Upgrade Does + +The upgrade script: +1. Deploys a new `DonationHandler` implementation with bug fixes +2. Updates the proxy to point to the new implementation +3. Preserves all existing state and data +4. Maintains the same proxy address for users + +See `script/UpgradeDonationHandler.s.sol` and `script/TestUpgrade.s.sol` for implementation details. + ## Export And Publish Export TypeScript interfaces from Solidity contracts and interfaces providing compatibility with TypeChain. Publish the exported packages to NPM. diff --git a/TESTNET_DEPLOYMENT.md b/TESTNET_DEPLOYMENT.md new file mode 100644 index 0000000..026d4bc --- /dev/null +++ b/TESTNET_DEPLOYMENT.md @@ -0,0 +1,339 @@ +# Testnet Deployment & Upgrade Guide + +This guide walks you through deploying DonationHandler to Sepolia testnet and testing the upgrade process before deploying to mainnet. + +**Why Test on Testnet First?** +- Verify deployment scripts work correctly +- Test upgrade process without risk +- Validate contract behavior changes +- Estimate gas costs +- Catch issues before mainnet + +**Scripts Used:** +- `script/DeployDonationHandler.s.sol` - Deploy to any network +- `script/UpgradeDonationHandler.s.sol` - Upgrade on any network + +## Prerequisites + +1. **Get Sepolia ETH** (for gas fees) + - Visit [Sepolia Faucet](https://sepoliafaucet.com/) + - Or [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) + - You'll need ~0.05 ETH for deployment + upgrade + +2. **Get an Etherscan API Key** (for verification) + - Sign up at [etherscan.io](https://etherscan.io/register) + - Create API key at https://etherscan.io/myapikey + +3. **Get a Sepolia RPC URL** + - [Alchemy](https://www.alchemy.com/): Free tier available + - [Infura](https://www.infura.io/): Free tier available + - Or use public RPC: `https://rpc.sepolia.org` + +## Step 1: Configure Environment + +Edit your `.env` file: + +```bash +# Add these to your .env file +PRIVATE_KEY=your_private_key_here +SEPOLIA_RPC=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY +ETHERSCAN_API_KEY=your_etherscan_api_key + +# These will be set after deployment +# PROXY_ADDRESS= +# PROXY_ADMIN_ADDRESS= +``` + +**⚠️ Security Note**: Never commit your `.env` file with real private keys! + +## Step 2: Check Your Balance + +```bash +# Source your environment +source .env + +# Check your balance on Sepolia +cast balance $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $SEPOLIA_RPC +``` + +You should see at least `50000000000000000` (0.05 ETH). + +## Step 3: Deploy to Sepolia + +```bash +# Deploy the contract +yarn deploy:sepolia +``` + +**Expected Output:** +``` +=== Deploying DonationHandler to Sepolia === +Deployer: 0x... +Implementation deployed to: 0x... +Proxy deployed to: 0x... +ProxyAdmin deployed to: 0x... + +=== Save these addresses for upgrading! === +export PROXY_ADDRESS= 0x... +export PROXY_ADMIN_ADDRESS= 0x... +``` + +## Step 4: Save Deployment Addresses + +Copy the addresses from the output and add them to your `.env` file: + +```bash +# Add these to .env +PROXY_ADDRESS=0x... # Copy from "Proxy deployed to" +PROXY_ADMIN_ADDRESS=0x... # Copy from "ProxyAdmin deployed to" +``` + +Or use the export commands directly: + +```bash +export PROXY_ADDRESS=0x... +export PROXY_ADMIN_ADDRESS=0x... +``` + +## Step 5: View on Etherscan + +1. Go to https://sepolia.etherscan.io/address/YOUR_PROXY_ADDRESS +2. You should see: + - Contract creation transaction + - Contract code (if verification succeeded) + - Ability to interact with the contract through the UI + +## Step 6: Verify Deployment on Etherscan + +1. Go to https://sepolia.etherscan.io/address/YOUR_PROXY_ADDRESS +2. Check that the contract is verified +3. View the contract's state and functions + +## Step 7: Test the Deployed Contract (Optional but Recommended) + +Test basic functionality to ensure the contract works: + +```bash +# Example: Make a simple donation +cast send $PROXY_ADDRESS \ + "donateETH(address,uint256,bytes)" \ + 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb \ + 1000000000000000 \ + 0x \ + --value 0.001ether \ + --private-key $PRIVATE_KEY \ + --rpc-url $SEPOLIA_RPC +``` + +Check the transaction on Etherscan to verify it succeeded. + +## Step 8: Record Current Implementation Address + +Before upgrading, save the current implementation address: + +```bash +# Get current implementation address +OLD_IMPL=$(cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $SEPOLIA_RPC) +echo "Old Implementation: $OLD_IMPL" +``` + +This will change after the upgrade, proving the upgrade worked. + +## Step 9: Upgrade the Contract + +Now upgrade to the new implementation: + +```bash +# Make sure PROXY_ADDRESS and PROXY_ADMIN_ADDRESS are set +source .env + +# Perform the upgrade +yarn upgrade:sepolia +``` + +**Expected Output:** +``` +=== Upgrading DonationHandler === +Proxy Address: 0x... +ProxyAdmin Address: 0x... +New Implementation deployed to: 0x... +Proxy upgraded successfully! +``` + +## Step 10: Verify the Upgrade Succeeded + +**Check 1: Implementation Address Changed** + +```bash +# Get new implementation address +NEW_IMPL=$(cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $SEPOLIA_RPC) +echo "New Implementation: $NEW_IMPL" + +# Compare with old implementation from Step 8 +# They should be DIFFERENT +``` + +**Check 2: Proxy Address Unchanged** + +The proxy address should be the same - users don't need to update anything. + +**Check 3: Contract State Preserved** + +The contract owner and all state should remain unchanged: + +```bash +# Check owner is still the same +cast call $PROXY_ADDRESS "owner()(address)" --rpc-url $SEPOLIA_RPC +``` + +**Check 4: Test Your Changes** + +Test the specific changes you made in this upgrade. This depends on what you changed: + +**Example A: Testing a bug fix** +```bash +# Try the scenario that was broken before +# It should now work correctly or revert with proper error +``` + +**Example B: Testing a new feature** +```bash +# Call the new function you added +cast send $PROXY_ADDRESS "newFunction(...)" ... +``` + +**Example C: Testing existing functionality still works** +```bash +# Make sure nothing broke +cast send $PROXY_ADDRESS \ + "donateETH(address,uint256,bytes)" \ + 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb \ + 1000000000000000 \ + 0x \ + --value 0.001ether \ + --private-key $PRIVATE_KEY \ + --rpc-url $SEPOLIA_RPC +``` + +If all checks pass, your upgrade is successful! βœ… + +## Step 11: Document Your Changes (Recommended) + +Before deploying to mainnet, document: + +1. **What changed** - List all modifications made to the implementation +2. **Why it changed** - Reason for the upgrade (bug fix, new feature, optimization) +3. **Testing results** - What you tested on testnet and the results +4. **Gas impact** - Compare gas costs before/after if relevant +5. **Breaking changes** - Any changes that affect how users interact with the contract + +This documentation helps with: +- Team review before mainnet deployment +- Communicating changes to users +- Future reference when doing more upgrades + +## Troubleshooting + +### "Insufficient funds" +- Check your balance: `cast balance $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $SEPOLIA_RPC` +- Get more Sepolia ETH from a faucet + +### "Invalid API Key" +- Verify your Etherscan API key is correct in `.env` +- Make sure you're using the API key, not the secret key + +### "Proxy address not set" +- Make sure you added `PROXY_ADDRESS` to your `.env` file after deployment +- Run `source .env` to reload environment variables + +### "Upgrade failed" or Permission Denied +- Verify you own the ProxyAdmin: `cast call $PROXY_ADMIN_ADDRESS "owner()(address)" --rpc-url $SEPOLIA_RPC` +- The returned address should match your deployer address +- If not, you're using the wrong private key or someone else owns the ProxyAdmin + +### "Implementation didn't change" +- Check that the upgrade transaction succeeded on Etherscan +- Verify you're calling the correct proxy address +- Make sure the upgrade script completed without errors + +### Contract behaves the same after upgrade +- Confirm you actually made changes to the implementation +- Check that you deployed a new implementation (not reusing old one) +- Verify the implementation address actually changed + +## Summary + +βœ… **What You Accomplished:** +1. βœ… Deployed DonationHandler implementation to testnet +2. βœ… Deployed TransparentUpgradeableProxy (ProxyAdmin created automatically) +3. βœ… Upgraded proxy to new implementation +4. βœ… Verified implementation changed +5. βœ… Confirmed proxy address unchanged (important for users!) +6. βœ… Validated contract state preserved +7. βœ… Tested new functionality works + +βœ… **Understanding the Upgrade Pattern:** + +**What Stays the Same:** +- βœ… Proxy address - Users keep using the same address +- βœ… ProxyAdmin address - Upgrade permissions unchanged +- βœ… Contract state - All data preserved (owner, balances, etc.) +- βœ… User experience - No action needed from users + +**What Changes:** +- βœ… Implementation address - Points to new code +- βœ… Contract logic - New features/fixes active +- βœ… Gas costs - May differ slightly with new code + +This is exactly how upgrades work on mainnet! The testnet deployment lets you verify everything before risking real funds. πŸš€ + +## Next Steps: Deploying to Mainnet + +Once you've successfully tested on Sepolia: + +### 1. Review and Prepare +- βœ… All tests passed on testnet +- βœ… Changes documented +- βœ… Team reviewed the upgrade +- βœ… Gas costs are acceptable +- βœ… No breaking changes for users + +### 2. Test on Mainnet Fork (Strongly Recommended) +```bash +# Test upgrade on a mainnet fork before real deployment +yarn upgrade:mainnet:fork +``` + +This runs against mainnet state without sending real transactions - catches issues specific to mainnet. + +### 3. Deploy to Mainnet +```bash +# When you're ready, follow the same process: +# 1. If first deployment: +# yarn deploy:mainnet (or your existing deployment process) +# +# 2. For upgrades: +# yarn upgrade:mainnet + +# IMPORTANT: Double-check you have the correct PROXY_ADDRESS +``` + +### 4. Verify on Mainnet +- Check implementation address changed +- Verify on Etherscan +- Test with a small transaction first +- Monitor for any issues + +### 5. Communicate (if needed) +- Notify users if there are changes they need to know about +- Update documentation +- Announce new features + +## Best Practices + +βœ… **Always test on testnet first** +βœ… **Use fork testing before mainnet** +βœ… **Have a rollback plan** (know the old implementation address) +βœ… **Monitor after deployment** +βœ… **Start with small transactions** to verify everything works +βœ… **Document every upgrade** diff --git a/package.json b/package.json index 2998e11..ae4e4d2 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,10 @@ "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "coverage": "forge coverage --ir-minimum --report summary --report lcov --match-path 'test/unit/*'", "deploy:mainnet": "bash -c 'source .env && forge script Deploy --rpc-url $MAINNET_RPC --account $MAINNET_DEPLOYER_NAME --broadcast --verify --chain mainnet -vvvvv'", - "deploy:sepolia": "bash -c 'source .env && forge script Deploy --rpc-url $SEPOLIA_RPC --account $SEPOLIA_DEPLOYER_NAME --broadcast --verify --chain sepolia -vvvvv'", + "deploy:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", + "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --sig \"upgradeOnEthereum(address)\" $PROXY_ADDRESS --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", + "upgrade:mainnet:fork": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --fork-url $MAINNET_RPC -vvvv'", + "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", "lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js", diff --git a/script/DeployDonationHandler.s.sol b/script/DeployDonationHandler.s.sol index ab7ec5d..bf606af 100644 --- a/script/DeployDonationHandler.s.sol +++ b/script/DeployDonationHandler.s.sol @@ -8,25 +8,44 @@ import {Script} from 'forge-std/Script.sol'; import {console} from 'forge-std/console.sol'; contract DeployDonationHandler is Script { - address public constant ethereumProxyAdmin = 0x7cD4eAAed06fA2270e0C063B7aBDa576a0ad149F; - address public constant gnosisProxyAdmin = 0x076C250700D210e6cf8A27D1EB1Fd754FB487986; - address public constant optimismProxyAdmin = 0x2f2c819210191750F2E11F7CfC5664a0eB4fd5e6; - address public constant polygonProxyAdmin = 0x7a5D2A00a25b95fd8739bc52Cd79f8F971C37Ca1; + address public constant ETHEREUM_PROXY_ADMIN = 0x7cD4eAAed06fA2270e0C063B7aBDa576a0ad149F; + address public constant GNOSIS_PROXY_ADMIN = 0x076C250700D210e6cf8A27D1EB1Fd754FB487986; + address public constant OPTIMISM_PROXY_ADMIN = 0x2f2c819210191750F2E11F7CfC5664a0eB4fd5e6; + address public constant POLYGON_PROXY_ADMIN = 0x7a5D2A00a25b95fd8739bc52Cd79f8F971C37Ca1; function run() external { - address deployer = vm.envAddress('PUBLIC_KEY'); uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); + address deployer = vm.addr(deployerPrivateKey); + + console.log('=== Deploying DonationHandler ==='); + console.log('Deployer:', deployer); + console.log('Deployer balance:', deployer.balance); vm.startBroadcast(deployerPrivateKey); - DonationHandler donationHandler = new DonationHandler(); + // Deploy implementation + DonationHandler implementation = new DonationHandler(); + console.log('Implementation deployed to:', address(implementation)); + // Deploy proxy (ProxyAdmin created automatically) TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( - address(donationHandler), address(deployer), abi.encodeWithSelector(DonationHandler.initialize.selector) + address(implementation), deployer, abi.encodeWithSelector(DonationHandler.initialize.selector) ); + console.log('Proxy deployed to:', address(proxy)); + + // Get ProxyAdmin address + bytes32 adminSlot = bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1); + address proxyAdmin = address(uint160(uint256(vm.load(address(proxy), adminSlot)))); + console.log('ProxyAdmin deployed to:', proxyAdmin); vm.stopBroadcast(); - console.log('DonationHandler Implementation deployed to:', address(donationHandler)); - console.log('TransparentUpgradeableProxy deployed to:', address(proxy)); + + console.log('\n=== Deployment Summary ==='); + console.log('Implementation:', address(implementation)); + console.log('Proxy:', address(proxy)); + console.log('ProxyAdmin:', proxyAdmin); + console.log('\n=== Save these for upgrading ==='); + console.log('export PROXY_ADDRESS=', address(proxy)); + console.log('export PROXY_ADMIN_ADDRESS=', proxyAdmin); } } diff --git a/script/TestUpgrade.s.sol b/script/TestUpgrade.s.sol new file mode 100644 index 0000000..a5a8920 --- /dev/null +++ b/script/TestUpgrade.s.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +import {DonationHandler} from '../src/contracts/DonationHandler.sol'; +import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; +import {ITransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; +import {Script} from 'forge-std/Script.sol'; +import {console} from 'forge-std/console.sol'; + +/// @title TestUpgrade +/// @notice Script to test the upgrade locally or on a fork before deploying to mainnet +contract TestUpgrade is Script { + function run() external { + address proxyAddress = vm.envAddress('PROXY_ADDRESS'); + address proxyAdminAddress = vm.envAddress('PROXY_ADMIN_ADDRESS'); + uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); + + console.log('=== Testing DonationHandler Upgrade ==='); + console.log('Proxy:', proxyAddress); + console.log('ProxyAdmin:', proxyAdminAddress); + + // Get current implementation before upgrade + DonationHandler proxy = DonationHandler(payable(proxyAddress)); + bytes32 implSlot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1); + address oldImplementation = address(uint160(uint256(vm.load(proxyAddress, implSlot)))); + console.log('Old Implementation:', oldImplementation); + + vm.startBroadcast(deployerPrivateKey); + + // Deploy new implementation + DonationHandler newImplementation = new DonationHandler(); + console.log('New Implementation:', address(newImplementation)); + + // Upgrade + ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress); + proxyAdmin.upgradeAndCall(ITransparentUpgradeableProxy(proxyAddress), address(newImplementation), ''); + + vm.stopBroadcast(); + + // Verify upgrade + address currentImplementation = address(uint160(uint256(vm.load(proxyAddress, implSlot)))); + console.log('Current Implementation:', currentImplementation); + + require(currentImplementation == address(newImplementation), 'Upgrade failed - implementation not updated'); + console.log('SUCCESS: Upgrade completed!'); + + // Test the new validation + console.log('\n=== Testing Bug Fix ==='); + _testBugFix(proxy); + } + + function _testBugFix(DonationHandler proxy) internal { + address recipient = address(0x1234567890123456789012345678901234567890); + + // Test 1: Should revert when amounts sum < totalAmount + console.log('Test 1: amounts sum < totalAmount should revert'); + address[] memory recipients1 = new address[](1); + recipients1[0] = recipient; + uint256[] memory amounts1 = new uint256[](1); + amounts1[0] = 8 ether; // Only 8 ETH allocated + bytes[] memory data1 = new bytes[](1); + + vm.expectRevert('Amounts do not match total'); + proxy.donateManyETH{value: 10 ether}(10 ether, recipients1, amounts1, data1); + console.log(' PASS: Correctly reverted'); + + // Test 2: Should revert when amounts sum > totalAmount + console.log('Test 2: amounts sum > totalAmount should revert'); + address[] memory recipients2 = new address[](1); + recipients2[0] = recipient; + uint256[] memory amounts2 = new uint256[](1); + amounts2[0] = 12 ether; // 12 ETH allocated + bytes[] memory data2 = new bytes[](1); + + vm.expectRevert('Amounts do not match total'); + proxy.donateManyETH{value: 10 ether}(10 ether, recipients2, amounts2, data2); + console.log(' PASS: Correctly reverted'); + + // Test 3: Should succeed when amounts sum == totalAmount + console.log('Test 3: amounts sum == totalAmount should succeed'); + address[] memory recipients3 = new address[](2); + recipients3[0] = recipient; + recipients3[1] = address(0x9876543210987654321098765432109876543210); + uint256[] memory amounts3 = new uint256[](2); + amounts3[0] = 6 ether; + amounts3[1] = 4 ether; // Total = 10 ETH + bytes[] memory data3 = new bytes[](2); + + uint256 contractBalanceBefore = address(proxy).balance; + proxy.donateManyETH{value: 10 ether}(10 ether, recipients3, amounts3, data3); + uint256 contractBalanceAfter = address(proxy).balance; + + require(contractBalanceAfter == contractBalanceBefore, 'ETH stuck in contract!'); + console.log(' PASS: Donation succeeded and no ETH stuck'); + + console.log('\n=== All Tests Passed! ==='); + } +} diff --git a/script/UpgradeDonationHandler.s.sol b/script/UpgradeDonationHandler.s.sol new file mode 100644 index 0000000..ad59e67 --- /dev/null +++ b/script/UpgradeDonationHandler.s.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +import {DonationHandler} from '../src/contracts/DonationHandler.sol'; +import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; +import {ITransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; +import {Script} from 'forge-std/Script.sol'; +import {console} from 'forge-std/console.sol'; + +contract UpgradeDonationHandler is Script { + // ProxyAdmin addresses for each network + address public constant ETHEREUM_PROXY_ADMIN = 0x7cD4eAAed06fA2270e0C063B7aBDa576a0ad149F; + address public constant GNOSIS_PROXY_ADMIN = 0x076C250700D210e6cf8A27D1EB1Fd754FB487986; + address public constant OPTIMISM_PROXY_ADMIN = 0x2f2c819210191750F2E11F7CfC5664a0eB4fd5e6; + address public constant POLYGON_PROXY_ADMIN = 0x7a5D2A00a25b95fd8739bc52Cd79f8F971C37Ca1; + + function run() external { + uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); + address proxyAddress = vm.envAddress('PROXY_ADDRESS'); + address proxyAdminAddress = vm.envAddress('PROXY_ADMIN_ADDRESS'); + + console.log('=== Upgrading DonationHandler ==='); + console.log('Proxy Address:', proxyAddress); + console.log('ProxyAdmin Address:', proxyAdminAddress); + + vm.startBroadcast(deployerPrivateKey); + + // Step 1: Deploy new implementation + DonationHandler newImplementation = new DonationHandler(); + console.log('New Implementation deployed to:', address(newImplementation)); + + // Step 2: Upgrade the proxy to point to new implementation + ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(proxyAddress), + address(newImplementation), + '' // No initialization data needed for upgrade + ); + + console.log('Proxy upgraded successfully!'); + console.log('Proxy now points to implementation:', address(newImplementation)); + + vm.stopBroadcast(); + } + + // Helper function to upgrade on a specific network + function upgradeOnEthereum(address proxyAddress) external { + _upgrade(proxyAddress, ETHEREUM_PROXY_ADMIN); + } + + function upgradeOnGnosis(address proxyAddress) external { + _upgrade(proxyAddress, GNOSIS_PROXY_ADMIN); + } + + function upgradeOnOptimism(address proxyAddress) external { + _upgrade(proxyAddress, OPTIMISM_PROXY_ADMIN); + } + + function upgradeOnPolygon(address proxyAddress) external { + _upgrade(proxyAddress, POLYGON_PROXY_ADMIN); + } + + function _upgrade(address proxyAddress, address proxyAdminAddress) internal { + uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); + + console.log('=== Upgrading DonationHandler ==='); + console.log('Proxy Address:', proxyAddress); + console.log('ProxyAdmin Address:', proxyAdminAddress); + + vm.startBroadcast(deployerPrivateKey); + + DonationHandler newImplementation = new DonationHandler(); + console.log('New Implementation deployed to:', address(newImplementation)); + + ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress); + proxyAdmin.upgradeAndCall( + ITransparentUpgradeableProxy(proxyAddress), + address(newImplementation), + '' + ); + + console.log('Proxy upgraded successfully!'); + + vm.stopBroadcast(); + } +} From 89ea882fd6ec68e3d88a8826fe30ba0aec86dae3 Mon Sep 17 00:00:00 2001 From: ali Date: Thu, 19 Feb 2026 05:08:54 +0330 Subject: [PATCH 02/14] chore: update .gitignore and package.json for local environment support - Added .env.local to .gitignore to prevent local environment files from being tracked. - Included a new script path for retrieving proxy addresses in package.json. --- .gitignore | 1 + PRODUCTION_UPGRADE.md | 310 ++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 312 insertions(+) create mode 100644 PRODUCTION_UPGRADE.md diff --git a/.gitignore b/.gitignore index 3c0f973..54351bd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ out-via-ir # Config files .env +.env.local # Avoid ignoring gitkeep !/**/.gitkeep diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md new file mode 100644 index 0000000..ddd2f59 --- /dev/null +++ b/PRODUCTION_UPGRADE.md @@ -0,0 +1,310 @@ +# Production Upgrade Guide + +This guide covers upgrading DonationHandler on all production networks. + +## 🎯 Networks to Upgrade + +Based on your deployments: +- βœ… Ethereum Mainnet (Chain ID: 1) +- βœ… Optimism (Chain ID: 10) +- βœ… Gnosis (Chain ID: 100) +- βœ… Base (Chain ID: 8453) +- βœ… Celo (Chain ID: 42220) + +## πŸ“‹ Pre-Upgrade Checklist + +- [ ] Successfully tested on Sepolia testnet +- [ ] All tests pass: `forge test -vvv` +- [ ] Code reviewed by team +- [ ] Changes documented in BUG_FIX_SUMMARY.md +- [ ] Fork test passed on mainnet +- [ ] Gas costs acceptable (~1.5M gas per network) +- [ ] Have sufficient ETH/native tokens on all networks + +## πŸ” Step 1: Find Your Proxy Addresses + +Your proxy addresses are in the broadcast folder. Let's extract them: + +```bash +# Ethereum Mainnet (Chain ID: 1) +ETHEREUM_PROXY=0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 +ETHEREUM_PROXY_ADMIN=0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409 + +# Check other networks in your broadcast folder: +cat broadcast/DeployDonationHandler.s.sol/10/run-latest.json | grep "contractAddress" # Optimism +cat broadcast/DeployDonationHandler.s.sol/100/run-latest.json | grep "contractAddress" # Gnosis +cat broadcast/DeployDonationHandler.s.sol/8453/run-latest.json | grep "contractAddress" # Base +cat broadcast/DeployDonationHandler.s.sol/42220/run-latest.json | grep "contractAddress" # Celo +``` + +## πŸš€ Step 2: Upgrade Ethereum Mainnet (Most Critical) + +### 2.1 Test on Fork First + +```bash +# Set environment +export PROXY_ADDRESS=0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 +export PROXY_ADMIN_ADDRESS=0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409 +export MAINNET_RPC=your_mainnet_rpc_url + +# Test on fork (SAFE - no real transactions) +yarn upgrade:mainnet:fork +``` + +**Expected Output:** +``` +=== Upgrading DonationHandler === +Proxy Address: 0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 +... +Proxy upgraded successfully! +``` + +### 2.2 Deploy to Mainnet + +If fork test passes: + +```bash +# REAL DEPLOYMENT - Double check everything! +source .env +yarn upgrade:mainnet +``` + +### 2.3 Verify Mainnet Upgrade + +```bash +# Check implementation changed +cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $MAINNET_RPC + +# Check on Etherscan +# Go to: https://etherscan.io/address/0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 + +# Test with small transaction first +cast send $PROXY_ADDRESS \ + "donateETH(address,uint256,bytes)" \ + 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb \ + 100000000000000 \ + 0x \ + --value 0.0001ether \ + --private-key $PRIVATE_KEY \ + --rpc-url $MAINNET_RPC +``` + +## 🌐 Step 3: Upgrade Other Networks + +Once Ethereum mainnet is successful, upgrade other networks. + +### Optimism (Chain ID: 10) + +```bash +# Setup +export PROXY_ADDRESS=YOUR_OPTIMISM_PROXY +export PROXY_ADMIN_ADDRESS=YOUR_OPTIMISM_PROXY_ADMIN +export OPTIMISM_RPC=your_optimism_rpc + +# Upgrade +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $OPTIMISM_RPC \ + --broadcast \ + --verify \ + -vvvv + +# Verify on Optimistic Etherscan +# https://optimistic.etherscan.io/address/YOUR_PROXY +``` + +### Gnosis (Chain ID: 100) + +```bash +# Setup +export PROXY_ADDRESS=YOUR_GNOSIS_PROXY +export PROXY_ADMIN_ADDRESS=0x076C250700D210e6cf8A27D1EB1Fd754FB487986 +export GNOSIS_RPC=https://rpc.gnosischain.com + +# Upgrade +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $GNOSIS_RPC \ + --broadcast \ + --verify \ + -vvvv + +# Verify on Gnosis Explorer +# https://gnosisscan.io/address/YOUR_PROXY +``` + +### Base (Chain ID: 8453) + +```bash +# Setup +export PROXY_ADDRESS=YOUR_BASE_PROXY +export PROXY_ADMIN_ADDRESS=YOUR_BASE_PROXY_ADMIN +export BASE_RPC=https://mainnet.base.org + +# Upgrade +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $BASE_RPC \ + --broadcast \ + --verify \ + -vvvv + +# Verify on Base Explorer +# https://basescan.org/address/YOUR_PROXY +``` + +### Celo (Chain ID: 42220) + +```bash +# Setup +export PROXY_ADDRESS=YOUR_CELO_PROXY +export PROXY_ADMIN_ADDRESS=YOUR_CELO_PROXY_ADMIN +export CELO_RPC=https://forno.celo.org + +# Upgrade +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $CELO_RPC \ + --broadcast \ + --verify \ + -vvvv + +# Verify on Celo Explorer +# https://celoscan.io/address/YOUR_PROXY +``` + +## βœ… Step 4: Post-Upgrade Verification (All Networks) + +For each network, verify: + +### 1. Implementation Changed +```bash +# Get new implementation +cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $RPC_URL +# Should be different from before +``` + +### 2. Contract Works +```bash +# Test with small transaction +cast send $PROXY_ADDRESS \ + "donateETH(address,uint256,bytes)" \ + TEST_ADDRESS \ + SMALL_AMOUNT \ + 0x \ + --value SMALL_AMOUNT \ + --private-key $PRIVATE_KEY \ + --rpc-url $RPC_URL +``` + +### 3. New Validation Works (Bug Fix Specific) +```bash +# This should REVERT with "Amounts do not match total" +cast send $PROXY_ADDRESS \ + "donateManyETH(uint256,address[],uint256[],bytes[])" \ + 1000000000000000000 \ + "[0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb]" \ + "[800000000000000000]" \ + "[]" \ + --value 1ether \ + --private-key $PRIVATE_KEY \ + --rpc-url $RPC_URL +``` + +## πŸ“Š Step 5: Monitor & Document + +### Monitor Each Network +- Check block explorers for upgrade transactions +- Monitor for any unusual activity +- Watch for user-reported issues + +### Document Deployment +Create a deployment record: + +```markdown +## Upgrade: Bug Fix - Amount Validation +Date: [DATE] +Deployed by: [YOUR_ADDRESS] + +### Networks Upgraded: +- [x] Ethereum: 0x... (Block: ..., Tx: ...) +- [x] Optimism: 0x... (Block: ..., Tx: ...) +- [x] Gnosis: 0x... (Block: ..., Tx: ...) +- [x] Base: 0x... (Block: ..., Tx: ...) +- [x] Celo: 0x... (Block: ..., Tx: ...) + +### Implementation Addresses: +- Ethereum: 0x... +- Optimism: 0x... +- Gnosis: 0x... +- Base: 0x... +- Celo: 0x... + +### Changes: +- Added amount sum validation in donateManyETH +- Added amount sum validation in donateManyERC20 +- Prevents fund lockup and theft vulnerability + +### Testing: +- βœ… All 42 tests pass +- βœ… Tested on Sepolia +- βœ… Fork tested on mainnet +- βœ… Verified on all networks + +### Gas Costs: +- Deploy implementation: ~1.4M gas +- Upgrade: ~50k gas +``` + +## ⚠️ Emergency Procedures + +### If Something Goes Wrong + +**Option 1: Rollback (if needed)** +```bash +# Can rollback to previous implementation if needed +# You saved the old implementation address, right? + +cast send $PROXY_ADMIN_ADDRESS \ + "upgradeAndCall(address,address,bytes)" \ + $PROXY_ADDRESS \ + $OLD_IMPLEMENTATION_ADDRESS \ + 0x \ + --private-key $PRIVATE_KEY \ + --rpc-url $RPC_URL +``` + +**Option 2: Pause & Investigate** +- Document the issue immediately +- Check transaction history on block explorer +- Compare behavior on working vs. failing network +- Test on fork to reproduce issue + +## πŸŽ‰ Success Checklist + +After all networks are upgraded: + +- [ ] All implementations verified on block explorers +- [ ] Tested on all networks with real transactions +- [ ] Bug fix works as expected (rejects invalid amounts) +- [ ] Normal operations work correctly +- [ ] No funds stuck in contracts +- [ ] Documentation updated +- [ ] Team notified +- [ ] Users informed (if necessary) + +## πŸ’‘ Tips + +1. **Start with Ethereum** - It's your most critical network +2. **Upgrade one network at a time** - Easier to troubleshoot +3. **Monitor between upgrades** - Wait 10-15 minutes, check for issues +4. **Save all transaction hashes** - For documentation and troubleshooting +5. **Test after each upgrade** - Don't assume it works +6. **Keep old implementation addresses** - In case you need to rollback + +## πŸ“ž Support + +If you encounter issues: +1. Check the Troubleshooting section in TESTNET_DEPLOYMENT.md +2. Review transaction on block explorer +3. Test on fork to reproduce +4. Check ProxyAdmin ownership +5. Verify gas prices aren't too high + +Remember: Take your time, verify each step, and don't rush! πŸš€ diff --git a/package.json b/package.json index ae4e4d2..81e42ab 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "coverage": "forge coverage --ir-minimum --report summary --report lcov --match-path 'test/unit/*'", "deploy:mainnet": "bash -c 'source .env && forge script Deploy --rpc-url $MAINNET_RPC --account $MAINNET_DEPLOYER_NAME --broadcast --verify --chain mainnet -vvvvv'", "deploy:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", + "addresses": "./scripts/get-proxy-addresses.sh", "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --sig \"upgradeOnEthereum(address)\" $PROXY_ADDRESS --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", "upgrade:mainnet:fork": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --fork-url $MAINNET_RPC -vvvv'", "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", From b0a1c466051eb980de9fbcdbe46ff1e634e00bb6 Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 24 Feb 2026 04:11:15 +0330 Subject: [PATCH 03/14] refactor: update upgrade scripts and documentation for clarity - Changed `upgrade:mainnet:fork` to `upgrade:mainnet:simulate` in package.json for consistency. - Updated documentation across README and PRODUCTION_UPGRADE.md to reflect the new simulate command. - Enhanced comments in deployment scripts for better understanding of deployment and upgrade processes. --- PRODUCTION_UPGRADE.md | 2 +- README.md | 6 ++-- TESTNET_DEPLOYMENT.md | 2 +- package.json | 4 +-- script/DeployDonationHandler.s.sol | 6 +++- script/UpgradeDonationHandler.s.sol | 48 +---------------------------- 6 files changed, 13 insertions(+), 55 deletions(-) diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md index ddd2f59..15c9050 100644 --- a/PRODUCTION_UPGRADE.md +++ b/PRODUCTION_UPGRADE.md @@ -48,7 +48,7 @@ export PROXY_ADMIN_ADDRESS=0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409 export MAINNET_RPC=your_mainnet_rpc_url # Test on fork (SAFE - no real transactions) -yarn upgrade:mainnet:fork +yarn upgrade:mainnet:simulate ``` **Expected Output:** diff --git a/README.md b/README.md index 40360b3..4453c0e 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ export PROXY_ADMIN_ADDRESS="0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409" export MAINNET_RPC="your_rpc_url" # 2. Test on fork first (SAFE - no real transactions) -yarn upgrade:mainnet:fork +yarn upgrade:mainnet:simulate # 3. If tests pass, upgrade on mainnet yarn upgrade:mainnet @@ -277,7 +277,7 @@ For other networks (Optimism, Gnosis, Polygon, Base, Celo), check your `broadcas yarn upgrade:mainnet # Test upgrade on fork before mainnet (recommended!) -yarn upgrade:mainnet:fork +yarn upgrade:mainnet:simulate ``` ### πŸ“ Manual Upgrade Process @@ -304,7 +304,7 @@ cast call $PROXY_ADDRESS "implementation()(address)" --rpc-url $MAINNET_RPC ### ⚠️ Important Notes -- **Test on fork first** - Always run `yarn upgrade:mainnet:fork` before mainnet +- **Test on fork first** - Always run `yarn upgrade:mainnet:simulate` before mainnet - **ProxyAdmin owner** - Ensure your account owns the ProxyAdmin contract - **Gas costs** - Expect ~1.45M gas (~0.05-0.1 ETH depending on gas prices) - **State preserved** - All existing data remains intact after upgrade diff --git a/TESTNET_DEPLOYMENT.md b/TESTNET_DEPLOYMENT.md index 026d4bc..9a8740c 100644 --- a/TESTNET_DEPLOYMENT.md +++ b/TESTNET_DEPLOYMENT.md @@ -301,7 +301,7 @@ Once you've successfully tested on Sepolia: ### 2. Test on Mainnet Fork (Strongly Recommended) ```bash # Test upgrade on a mainnet fork before real deployment -yarn upgrade:mainnet:fork +yarn upgrade:mainnet:simulate ``` This runs against mainnet state without sending real transactions - catches issues specific to mainnet. diff --git a/package.json b/package.json index 81e42ab..55b5c0b 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "deploy:mainnet": "bash -c 'source .env && forge script Deploy --rpc-url $MAINNET_RPC --account $MAINNET_DEPLOYER_NAME --broadcast --verify --chain mainnet -vvvvv'", "deploy:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", "addresses": "./scripts/get-proxy-addresses.sh", - "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --sig \"upgradeOnEthereum(address)\" $PROXY_ADDRESS --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", - "upgrade:mainnet:fork": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --fork-url $MAINNET_RPC -vvvv'", + "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", + "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", diff --git a/script/DeployDonationHandler.s.sol b/script/DeployDonationHandler.s.sol index bf606af..80afeef 100644 --- a/script/DeployDonationHandler.s.sol +++ b/script/DeployDonationHandler.s.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; +/// @notice Only run this script when you want a fresh deployment (new proxy + implementation). +/// For upgrading an existing proxy, use UpgradeDonationHandler.s.sol instead. + import {DonationHandler} from '../src/contracts/DonationHandler.sol'; import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; import {TransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; @@ -33,7 +36,8 @@ contract DeployDonationHandler is Script { ); console.log('Proxy deployed to:', address(proxy)); - // Get ProxyAdmin address + // EIP-1967 standard slot for transparent proxy admin (OpenZeppelin uses this) + // https://eips.ethereum.org/EIPS/eip-1967#admin-address bytes32 adminSlot = bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1); address proxyAdmin = address(uint160(uint256(vm.load(address(proxy), adminSlot)))); console.log('ProxyAdmin deployed to:', proxyAdmin); diff --git a/script/UpgradeDonationHandler.s.sol b/script/UpgradeDonationHandler.s.sol index ad59e67..a917052 100644 --- a/script/UpgradeDonationHandler.s.sol +++ b/script/UpgradeDonationHandler.s.sol @@ -8,12 +8,7 @@ import {Script} from 'forge-std/Script.sol'; import {console} from 'forge-std/console.sol'; contract UpgradeDonationHandler is Script { - // ProxyAdmin addresses for each network - address public constant ETHEREUM_PROXY_ADMIN = 0x7cD4eAAed06fA2270e0C063B7aBDa576a0ad149F; - address public constant GNOSIS_PROXY_ADMIN = 0x076C250700D210e6cf8A27D1EB1Fd754FB487986; - address public constant OPTIMISM_PROXY_ADMIN = 0x2f2c819210191750F2E11F7CfC5664a0eB4fd5e6; - address public constant POLYGON_PROXY_ADMIN = 0x7a5D2A00a25b95fd8739bc52Cd79f8F971C37Ca1; - + /// @notice Upgrade existing proxy. Set PROXY_ADDRESS and PROXY_ADMIN_ADDRESS in .env (or pass via CLI). function run() external { uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); address proxyAddress = vm.envAddress('PROXY_ADDRESS'); @@ -42,45 +37,4 @@ contract UpgradeDonationHandler is Script { vm.stopBroadcast(); } - - // Helper function to upgrade on a specific network - function upgradeOnEthereum(address proxyAddress) external { - _upgrade(proxyAddress, ETHEREUM_PROXY_ADMIN); - } - - function upgradeOnGnosis(address proxyAddress) external { - _upgrade(proxyAddress, GNOSIS_PROXY_ADMIN); - } - - function upgradeOnOptimism(address proxyAddress) external { - _upgrade(proxyAddress, OPTIMISM_PROXY_ADMIN); - } - - function upgradeOnPolygon(address proxyAddress) external { - _upgrade(proxyAddress, POLYGON_PROXY_ADMIN); - } - - function _upgrade(address proxyAddress, address proxyAdminAddress) internal { - uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); - - console.log('=== Upgrading DonationHandler ==='); - console.log('Proxy Address:', proxyAddress); - console.log('ProxyAdmin Address:', proxyAdminAddress); - - vm.startBroadcast(deployerPrivateKey); - - DonationHandler newImplementation = new DonationHandler(); - console.log('New Implementation deployed to:', address(newImplementation)); - - ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress); - proxyAdmin.upgradeAndCall( - ITransparentUpgradeableProxy(proxyAddress), - address(newImplementation), - '' - ); - - console.log('Proxy upgraded successfully!'); - - vm.stopBroadcast(); - } } From 629cebe32d3d3c7d440e0ea2bb1f89f5682a5f82 Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 24 Feb 2026 04:35:44 +0330 Subject: [PATCH 04/14] feat: add implementation deployment scripts and update documentation - Introduced new scripts for deploying the DonationHandler implementation on both mainnet and sepolia in package.json. - Expanded PRODUCTION_UPGRADE.md with instructions for deploying the implementation without ProxyAdmin access, including verification steps and handoff to the proxy owner. --- PRODUCTION_UPGRADE.md | 33 +++++++++++++++++++ package.json | 2 ++ .../DeployDonationHandlerImplementation.s.sol | 30 +++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 script/DeployDonationHandlerImplementation.s.sol diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md index 15c9050..fb6973e 100644 --- a/PRODUCTION_UPGRADE.md +++ b/PRODUCTION_UPGRADE.md @@ -21,6 +21,39 @@ Based on your deployments: - [ ] Gas costs acceptable (~1.5M gas per network) - [ ] Have sufficient ETH/native tokens on all networks +## πŸ”„ Alternative: Deploy implementation only (not the ProxyAdmin owner) + +If you don't have access to the ProxyAdmin owner key, you can still deploy and verify the new implementation. The proxy owner then performs the upgrade on their side. + +### 1. Deploy and verify the implementation + +```bash +source .env +yarn deploy:implementation:mainnet +# or for testnet first: yarn deploy:implementation:sepolia +``` + +The script will output the new implementation address. Save it (e.g. `export NEW_IMPLEMENTATION_ADDRESS=0x...`). + +### 2. Hand off to the proxy owner + +Send the **implementation address** to the ProxyAdmin owner. They should run: + +```solidity +proxyAdmin.upgrade(proxy, NEW_IMPLEMENTATION_ADDRESS); +``` + +Or via `cast`: + +```bash +cast send $PROXY_ADMIN_ADDRESS "upgrade(address,address)" $PROXY_ADDRESS $NEW_IMPLEMENTATION_ADDRESS \ + --rpc-url $MAINNET_RPC --private-key $OWNER_PRIVATE_KEY +``` + +No need for you to have proxy or ProxyAdmin addresses in `.env` for this flow; only `PRIVATE_KEY` and RPC URL are required to deploy and verify the implementation. + +--- + ## πŸ” Step 1: Find Your Proxy Addresses Your proxy addresses are in the broadcast folder. Let's extract them: diff --git a/package.json b/package.json index 55b5c0b..cd842ec 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", + "deploy:implementation:mainnet": "bash -c 'source .env && forge script script/DeployDonationHandlerImplementation.s.sol:DeployDonationHandlerImplementation --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", + "deploy:implementation:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandlerImplementation.s.sol:DeployDonationHandlerImplementation --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", "lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js", diff --git a/script/DeployDonationHandlerImplementation.s.sol b/script/DeployDonationHandlerImplementation.s.sol new file mode 100644 index 0000000..0db2238 --- /dev/null +++ b/script/DeployDonationHandlerImplementation.s.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +/// @notice Deploys and verifies only the DonationHandler implementation (no proxy, no upgrade). +/// Use this when you are not the ProxyAdmin owner: deploy + verify, then give the implementation +/// address to the owner so they can call proxyAdmin.upgrade(proxy, implementationAddress). + +import {DonationHandler} from '../src/contracts/DonationHandler.sol'; +import {Script} from 'forge-std/Script.sol'; +import {console} from 'forge-std/console.sol'; + +contract DeployDonationHandlerImplementation is Script { + function run() external { + uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); + + console.log('=== Deploying DonationHandler implementation only ==='); + + vm.startBroadcast(deployerPrivateKey); + + DonationHandler implementation = new DonationHandler(); + console.log('Implementation deployed to:', address(implementation)); + + vm.stopBroadcast(); + + console.log('\n=== Hand off to proxy owner ==='); + console.log('Give this address to the ProxyAdmin owner to run:'); + console.log(' proxyAdmin.upgrade(proxy,', address(implementation), ')'); + console.log('export NEW_IMPLEMENTATION_ADDRESS=', address(implementation)); + } +} From 3711eb30661cc3b84489cc582256df2fd21c5f62 Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 24 Feb 2026 16:38:58 +0330 Subject: [PATCH 05/14] feat: add new RPC endpoints and update deployment instructions - Added new RPC endpoints for Base, Arbitrum, Gnosis, Celo, Optimism, and Polygon in .env.example and foundry.toml. - Updated PRODUCTION_UPGRADE.md to reflect the new deployment command format for different chains. --- .env.example | 7 ++++++ PRODUCTION_UPGRADE.md | 6 +++-- foundry.toml | 12 ++++++++++ package.json | 3 +-- scripts/deploy-implementation.sh | 38 ++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 4 deletions(-) create mode 100755 scripts/deploy-implementation.sh diff --git a/.env.example b/.env.example index 14d938c..fb64cbc 100644 --- a/.env.example +++ b/.env.example @@ -4,4 +4,11 @@ MAINNET_DEPLOYER_NAME= SEPOLIA_RPC= SEPOLIA_DEPLOYER_NAME= +BASE_RPC= +ARBITRUM_RPC= +GNOSIS_RPC= +CELO_RPC= +OPTIMISM_RPC= +POLYGON_RPC= + ETHERSCAN_API_KEY= diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md index fb6973e..bff83d3 100644 --- a/PRODUCTION_UPGRADE.md +++ b/PRODUCTION_UPGRADE.md @@ -29,8 +29,10 @@ If you don't have access to the ProxyAdmin owner key, you can still deploy and v ```bash source .env -yarn deploy:implementation:mainnet -# or for testnet first: yarn deploy:implementation:sepolia +yarn deploy:implementation mainnet # Ethereum +yarn deploy:implementation base # Base +yarn deploy:implementation sepolia # Testnet first +# Add the chain name as the first argument. RPC must be set in .env as _RPC (e.g. BASE_RPC). ``` The script will output the new implementation address. Save it (e.g. `export NEW_IMPLEMENTATION_ADDRESS=0x...`). diff --git a/foundry.toml b/foundry.toml index b917daf..6e1d1bf 100644 --- a/foundry.toml +++ b/foundry.toml @@ -35,7 +35,19 @@ runs = 1000 [rpc_endpoints] mainnet = "${MAINNET_RPC}" sepolia = "${SEPOLIA_RPC}" +base = "${BASE_RPC}" +arbitrum = "${ARBITRUM_RPC}" +gnosis = "${GNOSIS_RPC}" +celo = "${CELO_RPC}" +optimism = "${OPTIMISM_RPC}" +polygon = "${POLYGON_RPC}" [etherscan] mainnet = { key = "${ETHERSCAN_API_KEY}" } sepolia = { key = "${ETHERSCAN_API_KEY}" } +base = { key = "${ETHERSCAN_API_KEY}", url = "https://api.basescan.org/api" } +arbitrum = { key = "${ETHERSCAN_API_KEY}", url = "https://api.arbiscan.io/api" } +gnosis = { key = "${ETHERSCAN_API_KEY}", url = "https://api.gnosisscan.io/api" } +celo = { key = "${ETHERSCAN_API_KEY}", url = "https://api.celoscan.io/api" } +optimism = { key = "${ETHERSCAN_API_KEY}", url = "https://api-optimistic.etherscan.io/api" } +polygon = { key = "${ETHERSCAN_API_KEY}", url = "https://api.polygonscan.com/api" } diff --git a/package.json b/package.json index cd842ec..690b3d2 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,7 @@ "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", - "deploy:implementation:mainnet": "bash -c 'source .env && forge script script/DeployDonationHandlerImplementation.s.sol:DeployDonationHandlerImplementation --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", - "deploy:implementation:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandlerImplementation.s.sol:DeployDonationHandlerImplementation --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", + "deploy:implementation": "./scripts/deploy-implementation.sh", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", "lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js", diff --git a/scripts/deploy-implementation.sh b/scripts/deploy-implementation.sh new file mode 100755 index 0000000..f7184d9 --- /dev/null +++ b/scripts/deploy-implementation.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e + +# Deploy DonationHandler implementation only (no proxy, no upgrade). +# Usage: ./scripts/deploy-implementation.sh +# Example: yarn deploy:implementation base (run from repo root with: yarn deploy:implementation -- base) +# +# Chain is passed as first argument. RPC URL is read from env: _RPC (e.g. BASE_RPC, MAINNET_RPC). +# Ensure the chain is in foundry.toml [rpc_endpoints] and [etherscan] for verification. + +CHAIN="${1:?Usage: deploy-implementation.sh (e.g. base, mainnet, sepolia)}" + +cd "$(dirname "$0")/.." +source .env + +# Derive RPC env var from chain name: base -> BASE_RPC, mainnet -> MAINNET_RPC +RPC_SUFFIX=$(echo "$CHAIN" | tr '[:lower:]' '[:upper:]' | tr '-' '_') +RPC_VAR="${RPC_SUFFIX}_RPC" + +if [[ -z "${!RPC_VAR}" ]]; then + echo "Error: $RPC_VAR is not set in .env" + exit 1 +fi + +# Chains that don't support EIP-1559 / eth_feeHistory need legacy transactions +LEGACY_CHAINS="celo gnosis" +LEGACY_FLAG="" +if [[ " $LEGACY_CHAINS " == *" $CHAIN "* ]]; then + LEGACY_FLAG="--legacy" +fi + +forge script script/DeployDonationHandlerImplementation.s.sol:DeployDonationHandlerImplementation \ + --rpc-url "${!RPC_VAR}" \ + --broadcast \ + --verify \ + --chain "$CHAIN" \ + $LEGACY_FLAG \ + -vvvv From b5196d5c1347e947ec50bc75e18184db4220160e Mon Sep 17 00:00:00 2001 From: ali Date: Fri, 27 Feb 2026 01:56:49 +0330 Subject: [PATCH 06/14] feat: enhance .env.example and package.json for upgrade process - Added new environment variables for Safe upgrade proposals in .env.example. - Updated .gitignore to include upgrade-payload.json. - Introduced new scripts in package.json for generating upgrade payloads and submitting upgrades to Safe. - Added dependencies for Safe API and protocol kits to support the new upgrade functionality. --- .env.example | 4 + .gitignore | 1 + docs/MULTISIG_UPGRADE_GUIDE.md | 127 ++++++++++++++++++++++++++ package.json | 8 +- scripts/generate-upgrade-payload.sh | 104 ++++++++++++++++++++++ scripts/submit-upgrade-to-safe.mjs | 133 ++++++++++++++++++++++++++++ 6 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 docs/MULTISIG_UPGRADE_GUIDE.md create mode 100755 scripts/generate-upgrade-payload.sh create mode 100644 scripts/submit-upgrade-to-safe.mjs diff --git a/.env.example b/.env.example index fb64cbc..bb40db4 100644 --- a/.env.example +++ b/.env.example @@ -11,4 +11,8 @@ CELO_RPC= OPTIMISM_RPC= POLYGON_RPC= +# For auto-proposing upgrade to Safe (proposer must be a Safe owner) +SAFE_ADDRESS= +PROPOSER_PRIVATE_KEY= + ETHERSCAN_API_KEY= diff --git a/.gitignore b/.gitignore index 54351bd..d0738ec 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ out-via-ir # Config files .env .env.local +upgrade-payload.json # Avoid ignoring gitkeep !/**/.gitkeep diff --git a/docs/MULTISIG_UPGRADE_GUIDE.md b/docs/MULTISIG_UPGRADE_GUIDE.md new file mode 100644 index 0000000..bd581c7 --- /dev/null +++ b/docs/MULTISIG_UPGRADE_GUIDE.md @@ -0,0 +1,127 @@ +# DonationHandler upgrade β€” guide for multisig signers + +This guide is for signers of the **ProxyAdmin** multisig. It explains how to run a single transaction to upgrade the DonationHandler to a new implementation. + +--- + +## Proposing the transaction (for the proposer) + +If you have the three addresses (ProxyAdmin, proxy, new implementation), you can **generate** the exact transaction payload and a Safe Transaction Builder–ready JSON: + +```bash +# From the repo root (requires Foundry cast) +yarn upgrade:generate-payload + +# Optional: add your Safe address and chain to get a direct link +yarn upgrade:generate-payload +# e.g. yarn upgrade:generate-payload 0xAdmin 0xProxy 0xImpl 0xYourSafe base +``` + +The script prints **To**, **Value**, **Data** and step-by-step Safe instructions. It also writes `upgrade-payload.json`, which you can **Import** in Safe β†’ Apps β†’ Transaction Builder to create the proposal in one click. + +### Submit proposal to Safe (proposer key in env) + +If the proposer’s private key is in `.env` as **`PROPOSER_PRIVATE_KEY`** (or **`PROPOSER_PK`**), and the proposer is one of the Safe owners, you can **submit** the proposal directly to the Safe Transaction Service: + +```bash +# Set in .env: SAFE_ADDRESS, PROXY_ADMIN_ADDRESS, PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS, PROPOSER_PRIVATE_KEY, and _RPC +yarn upgrade:submit-to-safe base +# or: mainnet, arbitrum, optimism, polygon, gnosis, celo, sepolia +``` + +The script will create the upgrade transaction, sign it with the proposer key, and POST it to the Safe API. Other signers can then confirm and execute in the Safe UI. + +--- + +## What you’re doing + +- The **DonationHandler** logic lives behind an upgradeable proxy. +- You will call **ProxyAdmin.upgrade(proxy, newImplementation)** so the proxy starts using the new implementation. +- Only the ProxyAdmin owner (your multisig) can do this. One transaction, no code β€” just the new implementation address. + +--- + +## What you need (you’ll receive these) + +| Item | Description | +|------|-------------| +| **ProxyAdmin address** | The contract your multisig owns (e.g. `0x...`) | +| **Proxy address** | The DonationHandler proxy to upgrade (e.g. `0x...`) | +| **New implementation address** | The newly deployed implementation (e.g. `0x...`) | +| **Network** | The chain where the proxy lives (e.g. Ethereum, Base, Celo) | + +--- + +## Steps (Gnosis Safe / Safe{Wallet}) + +1. Open your Safe for the correct network: + [https://app.safe.global](https://app.safe.global) (or your Safe URL). + +2. Go to **Apps** β†’ **Transaction Builder** (or **New transaction** β†’ **Contract interaction**). + +3. **To (contract):** + Paste the **ProxyAdmin** address. + +4. **Contract interaction:** + - Choose **Write contract** (or β€œContract interaction”). + - Find the function **`upgrade`** (or add it as a custom call; see below). + +5. **Function: `upgrade`** + - **Parameter 1 – `proxy` (address):** the **DonationHandler proxy** address. + - **Parameter 2 – `implementation` (address):** the **new implementation** address. + +6. **Value:** leave as **0**. + +7. Review the transaction, then **Create transaction** (or equivalent). Other signers **Sign** and execute when the threshold is met. + +--- + +## If the Safe UI doesn’t show `upgrade` + +Use **Contract interaction** with **Custom data**: + +- **To:** ProxyAdmin address +- **Data (hex):** use the ABI-encoded call: + + ```text + upgrade(address,address) + ``` + + Encoded with: + - **Selector:** `0x99...` (first 4 bytes of `keccak256("upgrade(address,address)")`). + You can get the exact calldata from a block explorer (e.g. Etherscan) by going to the ProxyAdmin contract β†’ **Write** β†’ **upgrade** and encoding the two addresses, or by using a small script/tool that encodes the call. + + Or use an online ABI encoder: + - Function: `upgrade(address proxy, address implementation)` + - Arguments: `[ , ]` + - Prepend the 4-byte selector: `0x99...` (look up `upgrade(address,address)` selector). + +--- + +## After the upgrade + +- The proxy address **does not change**; only the implementation it points to changes. +- You can confirm on a block explorer: open the **proxy** contract and check β€œImplementation” or β€œRead as Proxy” β€” it should show the new implementation address. +- If you have a changelog or release note for this upgrade, keep it for your records. + +--- + +## Checklist for proposer / first signer + +- [ ] Confirm **proxy**, **ProxyAdmin**, and **new implementation** addresses and **network** with the team. +- [ ] Confirm the new implementation is **verified** on the block explorer for that network. +- [ ] Create the Safe transaction as above and share the link or batch ID for other signers to sign. + +--- + +## Quick reference + +| Role | Address type | Example use | +|------|--------------|-------------| +| **ProxyAdmin** | Contract you call | β€œTo” in Safe = ProxyAdmin | +| **Proxy** | First argument of `upgrade` | DonationHandler proxy | +| **New implementation** | Second argument of `upgrade` | New implementation address | + +**Function:** `upgrade(address proxy, address implementation)` +**Value:** 0 +**Only the ProxyAdmin owner (your multisig) can call this.** diff --git a/package.json b/package.json index 690b3d2..fe2fdd4 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", "deploy:implementation": "./scripts/deploy-implementation.sh", + "upgrade:generate-payload": "./scripts/generate-upgrade-payload.sh", + "upgrade:submit-to-safe": "bash -c 'source .env && node scripts/submit-upgrade-to-safe.mjs \"$@\"' bash", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", "lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js", @@ -38,6 +40,9 @@ "package.json": "sort-package-json" }, "devDependencies": { + "@safe-global/api-kit": "^4.0.0", + "@safe-global/protocol-kit": "^4.0.0", + "@safe-global/types-kit": "^4.0.0", "@commitlint/cli": "19.3.0", "@commitlint/config-conventional": "19.2.2", "@defi-wonderland/natspec-smells": "1.1.6", @@ -46,6 +51,7 @@ "husky": ">=9", "lint-staged": ">=10", "solhint-community": "4.0.1", - "sort-package-json": "2.10.0" + "sort-package-json": "2.10.0", + "ethers": "^6.13.0" } } diff --git a/scripts/generate-upgrade-payload.sh b/scripts/generate-upgrade-payload.sh new file mode 100755 index 0000000..b2c9b47 --- /dev/null +++ b/scripts/generate-upgrade-payload.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -e + +# Generate the DonationHandler upgrade transaction payload for the multisig. +# Outputs calldata and a Safe Transaction Builder JSON so you can create the proposal in Safe. +# +# Usage: +# ./scripts/generate-upgrade-payload.sh [safe_address] [chain] +# Or set env vars: PROXY_ADMIN_ADDRESS, PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS +# Optional: SAFE_ADDRESS, CHAIN (for Safe app link) +# +# Example: +# NEW_IMPLEMENTATION_ADDRESS=0x... ./scripts/generate-upgrade-payload.sh 0xProxyAdmin 0xProxy +# ./scripts/generate-upgrade-payload.sh 0xAdmin 0xProxy 0xImpl 0xSafeAddress mainnet + +cd "$(dirname "$0")/.." + +PROXY_ADMIN="${1:-${PROXY_ADMIN_ADDRESS:?}}" +PROXY="${2:-${PROXY_ADDRESS:?}}" +NEW_IMPL="${3:-${NEW_IMPLEMENTATION_ADDRESS:?}}" +SAFE_ADDRESS="${4:-${SAFE_ADDRESS}}" +CHAIN="${5:-${CHAIN:-mainnet}}" + +# Normalize chain to Safe app slug (eth, base, arbitrum, etc.) +SAFE_CHAIN_SLUG="$CHAIN" +case "$CHAIN" in + mainnet) SAFE_CHAIN_SLUG="eth" ;; + polygon) SAFE_CHAIN_SLUG="matic" ;; + arbitrum) SAFE_CHAIN_SLUG="arbitrum" ;; + optimism) SAFE_CHAIN_SLUG="oeth" ;; + base) SAFE_CHAIN_SLUG="base" ;; + gnosis) SAFE_CHAIN_SLUG="gno" ;; + celo) SAFE_CHAIN_SLUG="celo" ;; +esac + +# Build calldata: upgrade(address proxy, address implementation) +CALLDATA=$(cast calldata "upgrade(address,address)" "$PROXY" "$NEW_IMPL") + +echo "" +echo "==============================================" +echo " DonationHandler upgrade β€” multisig payload" +echo "==============================================" +echo "" +echo " To (Contract): $PROXY_ADMIN" +echo " Value: 0" +echo " Data (calldata): $CALLDATA" +echo "" +echo " Function: upgrade(address proxy, address implementation)" +echo " proxy: $PROXY" +echo " implementation: $NEW_IMPL" +echo "" +echo "==============================================" +echo " How to propose in Safe" +echo "==============================================" +echo "" +if [[ -n "$SAFE_ADDRESS" ]]; then + echo " 1. Open your Safe: https://app.safe.global/home?safe=${SAFE_CHAIN_SLUG}:${SAFE_ADDRESS}" +else + echo " 1. Open your Safe (replace with your multisig address):" + echo " https://app.safe.global/home?safe=${SAFE_CHAIN_SLUG}:" +fi +echo " 2. New transaction β†’ Contract interaction" +echo " 3. Contract address: $PROXY_ADMIN" +echo " 4. Use ABI: upgrade(address,address) with:" +echo " proxy = $PROXY" +echo " implementation = $NEW_IMPL" +echo " 5. Or paste Raw data (hex): $CALLDATA" +echo " 6. Value: 0 β†’ Create transaction" +echo "" + +# Write JSON for Safe Transaction Builder (Apps β†’ Transaction Builder β†’ Import) +OUTPUT_JSON="${MULTISIG_PROPOSAL_JSON:-./upgrade-payload.json}" +cat > "$OUTPUT_JSON" << EOF +{ + "version": "1.0", + "chainId": "$CHAIN", + "meta": { + "name": "DonationHandler upgrade", + "description": "ProxyAdmin.upgrade(proxy, implementation)" + }, + "transactions": [ + { + "to": "$PROXY_ADMIN", + "value": "0", + "data": "$CALLDATA", + "contractMethod": { + "inputs": [ + { "name": "proxy", "type": "address" }, + { "name": "implementation", "type": "address" } + ], + "name": "upgrade", + "payable": false + }, + "contractInputsValues": { + "proxy": "$PROXY", + "implementation": "$NEW_IMPL" + } + } + ] +} +EOF +echo " Transaction Builder JSON: $OUTPUT_JSON" +echo " (Safe β†’ Apps β†’ Transaction Builder β†’ Import from file)" +echo "" diff --git a/scripts/submit-upgrade-to-safe.mjs b/scripts/submit-upgrade-to-safe.mjs new file mode 100644 index 0000000..06950b3 --- /dev/null +++ b/scripts/submit-upgrade-to-safe.mjs @@ -0,0 +1,133 @@ +#!/usr/bin/env node + +/** + * Submit the DonationHandler upgrade proposal to the Safe Transaction Service. + * Uses PROPOSER_PRIVATE_KEY (or PROPOSER_PK) from env. Proposer must be a Safe owner. + * + * Usage: + * node scripts/submit-upgrade-to-safe.mjs + * PROXY_ADMIN_ADDRESS=0x... PROXY_ADDRESS=0x... NEW_IMPLEMENTATION_ADDRESS=0x... SAFE_ADDRESS=0x... node scripts/submit-upgrade-to-safe.mjs base + * + * Required env: PROPOSER_PRIVATE_KEY (or PROPOSER_PK), SAFE_ADDRESS, PROXY_ADMIN_ADDRESS, PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS, + * and _RPC (e.g. BASE_RPC for chain=base). + */ + +// Env: source .env before running, or use node -r dotenv/config +import Safe from '@safe-global/protocol-kit'; +import SafeApiKit from '@safe-global/api-kit'; +import { OperationType } from '@safe-global/types-kit'; +import { ethers } from 'ethers'; + +const CHAIN_IDS = { + mainnet: 1, + sepolia: 11155111, + base: 8453, + arbitrum: 42161, + optimism: 10, + polygon: 137, + gnosis: 100, + celo: 42220, +}; + +const SAFE_APP_CHAIN_SLUG = { + mainnet: 'eth', + sepolia: 'sep', + base: 'base', + arbitrum: 'arbitrum', + optimism: 'oeth', + polygon: 'matic', + gnosis: 'gno', + celo: 'celo', +}; + +function getChainId(chain) { + const id = CHAIN_IDS[chain ? chain.toLowerCase() : 'mainnet']; + if (id == null) throw new Error(`Unknown chain: ${chain}. Supported: ${Object.keys(CHAIN_IDS).join(', ')}`); + return BigInt(id); +} + +function getRpcUrl(chain) { + const key = chain.toLowerCase().replace(/-/g, '_'); + const envKey = key === 'mainnet' ? 'MAINNET_RPC' : `${key.toUpperCase()}_RPC`; + const url = process.env[envKey]; + if (!url) throw new Error(`Missing ${envKey} in .env`); + return url; +} + +function getProposerPrivateKey() { + const key = process.env.PROPOSER_PRIVATE_KEY || process.env.PROPOSER_PK; + if (!key) throw new Error('Missing PROPOSER_PRIVATE_KEY or PROPOSER_PK in .env'); + return key.startsWith('0x') ? key : `0x${key}`; +} + +function main() { + const chain = process.argv[2] || process.env.CHAIN || 'mainnet'; + const safeAddress = process.env.SAFE_ADDRESS; + const proxyAdmin = process.env.PROXY_ADMIN_ADDRESS; + const proxy = process.env.PROXY_ADDRESS; + const newImplementation = process.env.NEW_IMPLEMENTATION_ADDRESS; + + if (!safeAddress || !proxyAdmin || !proxy || !newImplementation) { + console.error('Usage: node scripts/submit-upgrade-to-safe.mjs '); + console.error('Required env: SAFE_ADDRESS, PROXY_ADMIN_ADDRESS, PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS'); + console.error('Required env: PROPOSER_PRIVATE_KEY (or PROPOSER_PK) β€” proposer must be a Safe owner'); + console.error('Required env: _RPC (e.g. BASE_RPC)'); + process.exit(1); + } + + const chainId = getChainId(chain); + const rpcUrl = getRpcUrl(chain); + const proposerPk = getProposerPrivateKey(); + const proposerAddress = new ethers.Wallet(proposerPk).address; + + // Calldata: upgrade(address proxy, address implementation) + const iface = new ethers.Interface(['function upgrade(address proxy, address implementation)']); + const data = iface.encodeFunctionData('upgrade', [proxy, newImplementation]); + + const safeTransactionData = { + to: proxyAdmin, + value: '0', + data, + operation: OperationType.Call, + }; + + (async() => { + try { + const provider = new ethers.JsonRpcProvider(rpcUrl); + const protocolKit = await Safe.init({ + provider, + signer: proposerPk, + safeAddress, + }); + + const safeTransaction = await protocolKit.createTransaction({ + transactions: [safeTransactionData], + }); + const safeTxHash = await protocolKit.getTransactionHash(safeTransaction); + const signature = await protocolKit.signHash(safeTxHash); + + const apiKit = new SafeApiKit({ + chainId, + ...(process.env.SAFE_API_KEY && { apiKey: process.env.SAFE_API_KEY }), + }); + + await apiKit.proposeTransaction({ + safeAddress, + safeTransactionData: safeTransaction.data, + safeTxHash, + senderAddress: proposerAddress, + senderSignature: signature.data, + }); + + const slug = SAFE_APP_CHAIN_SLUG[chain ? chain.toLowerCase() : 'mainnet'] || 'eth'; + console.log('Proposal submitted to Safe Transaction Service.'); + console.log('Safe tx hash:', safeTxHash); + console.log('View in Safe:', `https://app.safe.global/transactions/queue?safe=${slug}:${safeAddress}`); + } catch (err) { + console.error('Propose failed:', err.message || err); + process.exit(1); + } + })(); +} + +main(); From 9c7e09591d4566734b1af3a7582411105584c1db Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 10 Mar 2026 17:55:54 +0330 Subject: [PATCH 07/14] feat: update upgrade process documentation and scripts - Added new parameters to .env.example for Safe upgrade proposals. - Modified package.json to streamline the upgrade submission script. - Expanded MULTISIG_UPGRADE_GUIDE.md with detailed steps for proposing upgrades. - Enhanced submit-upgrade-to-safe.mjs to load env and improve error messaging. Made-with: Cursor --- .env.example | 6 +- docs/MULTISIG_UPGRADE_GUIDE.md | 65 + package.json | 29 +- pnpm-lock.yaml | 3157 ++++++++++++++++++++++++++++ scripts/submit-upgrade-to-safe.mjs | 98 +- 5 files changed, 3326 insertions(+), 29 deletions(-) create mode 100644 pnpm-lock.yaml diff --git a/.env.example b/.env.example index bb40db4..5865918 100644 --- a/.env.example +++ b/.env.example @@ -11,8 +11,12 @@ CELO_RPC= OPTIMISM_RPC= POLYGON_RPC= -# For auto-proposing upgrade to Safe (proposer must be a Safe owner) +# For upgrade:submit-to-safe (proposer must be a Safe owner) SAFE_ADDRESS= +PROXY_ADMIN_ADDRESS= +PROXY_ADDRESS= +NEW_IMPLEMENTATION_ADDRESS= PROPOSER_PRIVATE_KEY= +SAFE_API_KEY= # required: get at https://developer.safe.global ETHERSCAN_API_KEY= diff --git a/docs/MULTISIG_UPGRADE_GUIDE.md b/docs/MULTISIG_UPGRADE_GUIDE.md index bd581c7..2c9bd19 100644 --- a/docs/MULTISIG_UPGRADE_GUIDE.md +++ b/docs/MULTISIG_UPGRADE_GUIDE.md @@ -4,6 +4,71 @@ This guide is for signers of the **ProxyAdmin** multisig. It explains how to run --- +## Steps to propose the transaction + +Choose one of two ways: **A) Submit from your machine** (script posts to Safe) or **B) Generate payload** then create the tx in the Safe UI. + +### Parameters and inputs you need + +| Parameter | Where to set | Description | +|-----------|----------------|--------------| +| **SAFE_ADDRESS** | `.env` or CLI | The multisig Safe address (owner of ProxyAdmin). | +| **PROXY_ADMIN_ADDRESS** | `.env` or CLI | The ProxyAdmin contract address. | +| **PROXY_ADDRESS** | `.env` or CLI | The DonationHandler proxy to upgrade. | +| **NEW_IMPLEMENTATION_ADDRESS** | `.env` or CLI | The new implementation contract address (from `yarn deploy:implementation `). | +| **PROPOSER_PRIVATE_KEY** (or **PROPOSER_PK**) | `.env` only | Private key of a Safe **owner** (used only for **Option A**). | +| **<CHAIN>_RPC** | `.env` | RPC URL for the chain, e.g. `BASE_RPC`, `MAINNET_RPC`. | +| **CHAIN** | CLI argument or `.env` | Chain name: `mainnet`, `base`, `arbitrum`, `optimism`, `polygon`, `gnosis`, `celo`, `sepolia`. | +| **SAFE_API_KEY** | `.env` (optional) | Safe API key if you hit rate limits. | + +--- + +### Option A β€” Submit proposal from your machine (recommended if you have proposer key) + +1. **Set in `.env`:** + - `SAFE_ADDRESS` = your multisig address + - `PROXY_ADMIN_ADDRESS` = ProxyAdmin contract + - `PROXY_ADDRESS` = DonationHandler proxy + - `NEW_IMPLEMENTATION_ADDRESS` = new implementation (from deploy) + - `PROPOSER_PRIVATE_KEY` or `PROPOSER_PK` = private key of **one Safe owner** + - `_RPC` = RPC URL (e.g. `BASE_RPC`, `MAINNET_RPC`) + +2. **Run (from repo root):** + ```bash + yarn upgrade:submit-to-safe base + ``` + Use the correct chain instead of `base` if needed (e.g. `mainnet`, `arbitrum`). + +3. The script will create the upgrade tx, sign it with the proposer key, and submit it to the Safe Transaction Service. Other signers see it in the Safe UI and can confirm/execute. + +--- + +### Option B β€” Generate payload, then create the tx in Safe UI + +1. **Set in `.env` (or pass as CLI args):** + - `PROXY_ADMIN_ADDRESS` + - `PROXY_ADDRESS` + - `NEW_IMPLEMENTATION_ADDRESS` + Optional: `SAFE_ADDRESS`, `CHAIN` (for the printed Safe link). + +2. **Generate the payload:** + ```bash + yarn upgrade:generate-payload 0x 0x 0x + # Or with env set: yarn upgrade:generate-payload + ``` + +3. **Use the output:** + - Open the printed Safe link (or [app.safe.global](https://app.safe.global)). + - **New transaction** β†’ **Contract interaction** (or **Apps** β†’ **Transaction Builder**). + - **To:** paste `PROXY_ADMIN_ADDRESS`. + - **Data:** paste the hex **Data (calldata)** from the script output, or use the function `upgrade(address,address)` with `proxy` = `PROXY_ADDRESS` and `implementation` = `NEW_IMPLEMENTATION_ADDRESS`. + - **Value:** 0. + - **Create transaction** so other signers can sign and execute. + + Alternatively, in Safe go to **Apps** β†’ **Transaction Builder** β†’ **Import** and select the generated `upgrade-payload.json`. + +--- + ## Proposing the transaction (for the proposer) If you have the three addresses (ProxyAdmin, proxy, new implementation), you can **generate** the exact transaction payload and a Safe Transaction Builder–ready JSON: diff --git a/package.json b/package.json index fe2fdd4..16ab8b5 100644 --- a/package.json +++ b/package.json @@ -10,18 +10,13 @@ "license": "MIT", "author": "Wonderland", "scripts": { + "addresses": "./scripts/get-proxy-addresses.sh", "build": "forge build", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "coverage": "forge coverage --ir-minimum --report summary --report lcov --match-path 'test/unit/*'", + "deploy:implementation": "./scripts/deploy-implementation.sh", "deploy:mainnet": "bash -c 'source .env && forge script Deploy --rpc-url $MAINNET_RPC --account $MAINNET_DEPLOYER_NAME --broadcast --verify --chain mainnet -vvvvv'", "deploy:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", - "addresses": "./scripts/get-proxy-addresses.sh", - "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", - "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", - "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", - "deploy:implementation": "./scripts/deploy-implementation.sh", - "upgrade:generate-payload": "./scripts/generate-upgrade-payload.sh", - "upgrade:submit-to-safe": "bash -c 'source .env && node scripts/submit-upgrade-to-safe.mjs \"$@\"' bash", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", "lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js", @@ -32,7 +27,12 @@ "test:integration": "forge test --match-contract Integration -vvv", "test:symbolic": "halmos", "test:unit": "forge test --match-contract Unit -vvv", - "test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit" + "test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit", + "upgrade:generate-payload": "./scripts/generate-upgrade-payload.sh", + "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", + "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", + "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", + "upgrade:submit-to-safe": "node scripts/submit-upgrade-to-safe.mjs" }, "lint-staged": { "*.{js,css,md,ts,sol}": "forge fmt", @@ -40,18 +40,19 @@ "package.json": "sort-package-json" }, "devDependencies": { - "@safe-global/api-kit": "^4.0.0", - "@safe-global/protocol-kit": "^4.0.0", - "@safe-global/types-kit": "^4.0.0", "@commitlint/cli": "19.3.0", "@commitlint/config-conventional": "19.2.2", "@defi-wonderland/natspec-smells": "1.1.6", - "forge-std": "github:foundry-rs/forge-std#1.9.2", + "@safe-global/api-kit": "^4.0.0", + "@safe-global/protocol-kit": "^4.0.0", + "@safe-global/types-kit": "^3.0.0", + "dotenv": "^16.4.5", + "ethers": "^6.13.0", + "forge-std": "github:foundry-rs/forge-std#v1.9.2", "halmos-cheatcodes": "github:a16z/halmos-cheatcodes#c0d8655", "husky": ">=9", "lint-staged": ">=10", "solhint-community": "4.0.1", - "sort-package-json": "2.10.0", - "ethers": "^6.13.0" + "sort-package-json": "2.10.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..3f238c8 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3157 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@commitlint/cli': + specifier: 19.3.0 + version: 19.3.0(@types/node@25.3.2)(typescript@5.9.3) + '@commitlint/config-conventional': + specifier: 19.2.2 + version: 19.2.2 + '@defi-wonderland/natspec-smells': + specifier: 1.1.6 + version: 1.1.6(typescript@5.9.3)(zod@3.25.76) + '@safe-global/api-kit': + specifier: ^4.0.0 + version: 4.0.1(typescript@5.9.3)(zod@3.25.76) + '@safe-global/protocol-kit': + specifier: ^4.0.0 + version: 4.1.7(typescript@5.9.3)(zod@3.25.76) + '@safe-global/types-kit': + specifier: ^3.0.0 + version: 3.0.0(typescript@5.9.3)(zod@3.25.76) + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + ethers: + specifier: ^6.13.0 + version: 6.16.0 + forge-std: + specifier: github:foundry-rs/forge-std#v1.9.2 + version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/1714bee72e286e73f76e320d110e0eaf5c4e649d + halmos-cheatcodes: + specifier: github:a16z/halmos-cheatcodes#c0d8655 + version: halmos-cheatcodes#c0d8655@https://codeload.github.com/a16z/halmos-cheatcodes/tar.gz/c0d8655 + husky: + specifier: '>=9' + version: 9.1.7 + lint-staged: + specifier: '>=10' + version: 16.2.7 + solhint-community: + specifier: 4.0.1 + version: 4.0.1(typescript@5.9.3) + sort-package-json: + specifier: 2.10.0 + version: 2.10.0 + +packages: + + '@adraffy/ens-normalize@1.10.1': + resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + + '@adraffy/ens-normalize@1.11.1': + resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@commitlint/cli@19.3.0': + resolution: {integrity: sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==} + engines: {node: '>=v18'} + hasBin: true + + '@commitlint/config-conventional@19.2.2': + resolution: {integrity: sha512-mLXjsxUVLYEGgzbxbxicGPggDuyWNkf25Ht23owXIH+zV2pv1eJuzLK3t1gDY5Gp6pxdE60jZnWUY5cvgL3ufw==} + engines: {node: '>=v18'} + + '@commitlint/config-validator@19.8.1': + resolution: {integrity: sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==} + engines: {node: '>=v18'} + + '@commitlint/ensure@19.8.1': + resolution: {integrity: sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==} + engines: {node: '>=v18'} + + '@commitlint/execute-rule@19.8.1': + resolution: {integrity: sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==} + engines: {node: '>=v18'} + + '@commitlint/format@19.8.1': + resolution: {integrity: sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==} + engines: {node: '>=v18'} + + '@commitlint/is-ignored@19.8.1': + resolution: {integrity: sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==} + engines: {node: '>=v18'} + + '@commitlint/lint@19.8.1': + resolution: {integrity: sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==} + engines: {node: '>=v18'} + + '@commitlint/load@19.8.1': + resolution: {integrity: sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==} + engines: {node: '>=v18'} + + '@commitlint/message@19.8.1': + resolution: {integrity: sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==} + engines: {node: '>=v18'} + + '@commitlint/parse@19.8.1': + resolution: {integrity: sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==} + engines: {node: '>=v18'} + + '@commitlint/read@19.8.1': + resolution: {integrity: sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==} + engines: {node: '>=v18'} + + '@commitlint/resolve-extends@19.8.1': + resolution: {integrity: sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==} + engines: {node: '>=v18'} + + '@commitlint/rules@19.8.1': + resolution: {integrity: sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==} + engines: {node: '>=v18'} + + '@commitlint/to-lines@19.8.1': + resolution: {integrity: sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==} + engines: {node: '>=v18'} + + '@commitlint/top-level@19.8.1': + resolution: {integrity: sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==} + engines: {node: '>=v18'} + + '@commitlint/types@19.8.1': + resolution: {integrity: sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==} + engines: {node: '>=v18'} + + '@defi-wonderland/natspec-smells@1.1.6': + resolution: {integrity: sha512-HTdZLEdBs3UakW0JQZ7vO8pb6YCoU3CPQNfLxa0Z9PWAwmgKhSZJbF8dm/okkJEJGRa0dCoOxviJw5jeK+kDiQ==} + hasBin: true + + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.2.0': + resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + + '@noble/curves@1.9.1': + resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.3.2': + resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} + engines: {node: '>= 16'} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@safe-global/api-kit@4.0.1': + resolution: {integrity: sha512-pNtDLgMHlCSr4Hwwe6jsnvMheAu2SZCTqjYlnNe4cKH2pSKINVRTiILoeJ0wOpixrMCH4NlgJ+9N3QruRNcCpQ==} + + '@safe-global/protocol-kit@4.1.7': + resolution: {integrity: sha512-4VMqbezB91JasxhOB2HhRjsCeuxBMnPdUMXh5eKEs59xE86Ys2GhQ7+xk78qaB9SKUe74wKaQAeKE+hC7nHffA==} + + '@safe-global/protocol-kit@6.1.2': + resolution: {integrity: sha512-cTpPdUAS2AMfGCkD1T601rQNjT0rtMQLA2TH7L/C+iFPAC6WrrDFop2B9lzeHjczlnVzrRpfFe4cL1bLrJ9NZw==} + + '@safe-global/safe-core-sdk-types@5.1.0': + resolution: {integrity: sha512-UzXR4zWmVzux25FcIm4H049QhZZpVpIBL5HE+V0p5gHpArZROL+t24fZmsKUf403CtBxIJM5zZSVQL0nFJi+IQ==} + deprecated: 'WARNING: This project has been renamed to @safe-global/types-kit. Please, migrate from @safe-global/safe-core-sdk-types@5.1.0 to @safe-global/types-kit@1.0.0.' + + '@safe-global/safe-deployments@1.37.51': + resolution: {integrity: sha512-w+p9XOtoS6j0sN57zfKkSGz2ts0blf+gzVZz5sqKUlov4wsSJdqtaUPcNJnKvpV8x1aes/k1Do7qJMBvJivPtQ==} + + '@safe-global/safe-modules-deployments@2.2.23': + resolution: {integrity: sha512-73V/PM3ire3Xc2JacalHEif3E3zyIF5xpJ9c0MVrzK3eS5S04CaTaTH/Sy6kCqh4g5fmJp/8Mc4hs20Op/Cd6A==} + + '@safe-global/types-kit@3.0.0': + resolution: {integrity: sha512-AZWIlR5MguDPdGiOj7BB4JQPY2afqmWQww1mu8m8Oi16HHBW99G01kFOu4NEHBwEU1cgwWOMY19hsI5KyL4W2w==} + + '@scure/base@1.1.9': + resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} + + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} + + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + + '@solidity-parser/parser@0.19.0': + resolution: {integrity: sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==} + + '@types/bn.js@5.2.0': + resolution: {integrity: sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==} + + '@types/conventional-commits-parser@5.0.2': + resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} + + '@types/node@22.7.5': + resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + + '@types/node@25.3.2': + resolution: {integrity: sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==} + + '@types/pbkdf2@3.1.2': + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + + '@types/secp256k1@4.0.7': + resolution: {integrity: sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw==} + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + abitype@0.7.1: + resolution: {integrity: sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ==} + peerDependencies: + typescript: '>=4.9.4' + zod: ^3 >=3.19.1 + peerDependenciesMeta: + zod: + optional: true + + abitype@1.2.3: + resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + antlr4@4.13.2: + resolution: {integrity: sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==} + engines: {node: '>=16'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + asn1js@3.0.7: + resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} + engines: {node: '>=12.0.0'} + + ast-parents@0.0.1: + resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.11: + resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + + bn.js@5.2.3: + resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + cipher-base@1.0.7: + resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} + engines: {node: '>= 0.10'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@5.1.1: + resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} + engines: {node: '>=20'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + conventional-changelog-angular@7.0.0: + resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} + engines: {node: '>=16'} + + conventional-changelog-conventionalcommits@7.0.2: + resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} + engines: {node: '>=16'} + + conventional-commits-parser@5.0.0: + resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} + engines: {node: '>=16'} + hasBin: true + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig-typescript-loader@6.2.0: + resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==} + engines: {node: '>=v18'} + peerDependencies: + '@types/node': '*' + cosmiconfig: '>=9' + typescript: '>=5' + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + dargs@8.1.0: + resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} + engines: {node: '>=12'} + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-file@1.0.0: + resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} + engines: {node: '>=0.10.0'} + + detect-indent@7.0.2: + resolution: {integrity: sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==} + engines: {node: '>=12.20'} + + detect-newline@4.0.1: + resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + + ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} + + ethers@6.16.0: + resolution: {integrity: sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==} + engines: {node: '>=14.0.0'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + + findup-sync@5.0.0: + resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} + engines: {node: '>= 10.13.0'} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/1714bee72e286e73f76e320d110e0eaf5c4e649d: + resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/1714bee72e286e73f76e320d110e0eaf5c4e649d} + version: 1.9.2 + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stdin@9.0.0: + resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} + engines: {node: '>=12'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + git-hooks-list@3.2.0: + resolution: {integrity: sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==} + + git-raw-commits@4.0.0: + resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} + engines: {node: '>=16'} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + + global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + + globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + halmos-cheatcodes#c0d8655@https://codeload.github.com/a16z/halmos-cheatcodes/tar.gz/c0d8655: + resolution: {tarball: https://codeload.github.com/a16z/halmos-cheatcodes/tar.gz/c0d8655} + version: 0.0.0 + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hash-base@3.1.2: + resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} + engines: {node: '>= 0.8'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-text-path@2.0.0: + resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} + engines: {node: '>=8'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isows@1.0.7: + resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} + peerDependencies: + ws: '*' + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsel@1.1.6: + resolution: {integrity: sha512-7E6r8kVzjmKhwXR/82Z+43edfOJGRvLvx6cJZ+SS2MGAPPtYZGnaIsFHpQMA1IbIPA9twDProkob4IIAJ0ZqSw==} + engines: {node: '>=0.10.0'} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lint-staged@16.2.7: + resolution: {integrity: sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==} + engines: {node: '>=20.17'} + hasBin: true + + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + + lodash@4.17.23: + resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + nano-spawn@2.0.0: + resolution: {integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==} + engines: {node: '>=20.17'} + + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + + node-addon-api@5.1.0: + resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + ox@0.12.4: + resolution: {integrity: sha512-+P+C7QzuwPV8lu79dOwjBKfB2CbnbEXe/hfyyrff1drrO1nOOj3Hc87svHfcW1yneRr3WXaKr6nz11nq+/DF9Q==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pbkdf2@3.1.5: + resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} + engines: {node: '>= 0.10'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + ripemd160@2.0.3: + resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} + engines: {node: '>= 0.8'} + + rlp@2.2.7: + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + secp256k1@4.0.4: + resolution: {integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==} + engines: {node: '>=18.0.0'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + + solc-typed-ast@18.2.4: + resolution: {integrity: sha512-HTkr6b2WMSJ3pgVRf5us/UWjCvfSlvE1yUcHna+miSPerkyppGnZQaJWqrcECa7ZjxmSV7H2buUDKux9hR4ivg==} + hasBin: true + + solc@0.8.25: + resolution: {integrity: sha512-7P0TF8gPeudl1Ko3RGkyY6XVCxe2SdD/qQhtns1vl3yAbK/PDifKDLHGtx1t7mX3LgR7ojV7Fg/Kc6Q9D2T8UQ==} + engines: {node: '>=10.0.0'} + hasBin: true + + solhint-community@4.0.1: + resolution: {integrity: sha512-kxgl+czm9EvABRmzOpfATSQPttu/I0OooOoHlcu2DCCqETiMFFi8zAMgAWu96qWUnzAWHbWgshGnDeAYk/FTuQ==} + hasBin: true + + sort-object-keys@1.1.3: + resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} + + sort-package-json@2.10.0: + resolution: {integrity: sha512-MYecfvObMwJjjJskhxYfuOADkXp1ZMMnCFC8yhp+9HDsk7HhR336hd7eiBs96lTXfiqmUNI+WQCeCMRBhl251g==} + hasBin: true + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + src-location@1.1.0: + resolution: {integrity: sha512-idBVZgLZGzB3B2Et317AFDQto7yRgp1tOuFd+VKIH2dw1jO1b6p07zNjtQoVhkW+CY6oGTp9Y5UIfbJoZRsoFQ==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.0: + resolution: {integrity: sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==} + engines: {node: '>=20'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + text-extensions@2.4.0: + resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} + engines: {node: '>= 0.4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + viem@2.46.3: + resolution: {integrity: sha512-2LJS+Hyh2sYjHXQtzfv1kU9pZx9dxFzvoU/ZKIcn0FNtOU0HQuIICuYdWtUDFHaGXbAdVo8J1eCvmjkL9JVGwg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + + web3-errors@1.3.1: + resolution: {integrity: sha512-w3NMJujH+ZSW4ltIZZKtdbkbyQEvBzyp3JRn59Ckli0Nz4VMsVq8aF1bLWM7A2kuQ+yVEm3ySeNU+7mSRwx7RQ==} + engines: {node: '>=14', npm: '>=6.12.0'} + + web3-eth-abi@4.4.1: + resolution: {integrity: sha512-60ecEkF6kQ9zAfbTY04Nc9q4eEYM0++BySpGi8wZ2PD1tw/c0SDvsKhV6IKURxLJhsDlb08dATc3iD6IbtWJmg==} + engines: {node: '>=14', npm: '>=6.12.0'} + + web3-types@1.10.0: + resolution: {integrity: sha512-0IXoaAFtFc8Yin7cCdQfB9ZmjafrbP6BO0f0KT/khMhXKUpoJ6yShrVhiNpyRBo8QQjuOagsWzwSK2H49I7sbw==} + engines: {node: '>=14', npm: '>=6.12.0'} + + web3-utils@4.3.3: + resolution: {integrity: sha512-kZUeCwaQm+RNc2Bf1V3BYbF29lQQKz28L0y+FA4G0lS8IxtJVGi5SeDTUkpwqqkdHHC7JcapPDnyyzJ1lfWlOw==} + engines: {node: '>=14', npm: '>=6.12.0'} + + web3-validator@2.0.6: + resolution: {integrity: sha512-qn9id0/l1bWmvH4XfnG/JtGKKwut2Vokl6YXP5Kfg424npysmtRLe9DgiNBM9Op7QL/aSiaA0TVXibuIuWcizg==} + engines: {node: '>=14', npm: '>=6.12.0'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + 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 + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@adraffy/ens-normalize@1.10.1': {} + + '@adraffy/ens-normalize@1.11.1': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.28.5': {} + + '@commitlint/cli@19.3.0(@types/node@25.3.2)(typescript@5.9.3)': + dependencies: + '@commitlint/format': 19.8.1 + '@commitlint/lint': 19.8.1 + '@commitlint/load': 19.8.1(@types/node@25.3.2)(typescript@5.9.3) + '@commitlint/read': 19.8.1 + '@commitlint/types': 19.8.1 + execa: 8.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/config-conventional@19.2.2': + dependencies: + '@commitlint/types': 19.8.1 + conventional-changelog-conventionalcommits: 7.0.2 + + '@commitlint/config-validator@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + ajv: 8.18.0 + + '@commitlint/ensure@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + '@commitlint/execute-rule@19.8.1': {} + + '@commitlint/format@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + chalk: 5.6.2 + + '@commitlint/is-ignored@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + semver: 7.7.4 + + '@commitlint/lint@19.8.1': + dependencies: + '@commitlint/is-ignored': 19.8.1 + '@commitlint/parse': 19.8.1 + '@commitlint/rules': 19.8.1 + '@commitlint/types': 19.8.1 + + '@commitlint/load@19.8.1(@types/node@25.3.2)(typescript@5.9.3)': + dependencies: + '@commitlint/config-validator': 19.8.1 + '@commitlint/execute-rule': 19.8.1 + '@commitlint/resolve-extends': 19.8.1 + '@commitlint/types': 19.8.1 + chalk: 5.6.2 + cosmiconfig: 9.0.0(typescript@5.9.3) + cosmiconfig-typescript-loader: 6.2.0(@types/node@25.3.2)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3) + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + lodash.uniq: 4.5.0 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/message@19.8.1': {} + + '@commitlint/parse@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + conventional-changelog-angular: 7.0.0 + conventional-commits-parser: 5.0.0 + + '@commitlint/read@19.8.1': + dependencies: + '@commitlint/top-level': 19.8.1 + '@commitlint/types': 19.8.1 + git-raw-commits: 4.0.0 + minimist: 1.2.8 + tinyexec: 1.0.2 + + '@commitlint/resolve-extends@19.8.1': + dependencies: + '@commitlint/config-validator': 19.8.1 + '@commitlint/types': 19.8.1 + global-directory: 4.0.1 + import-meta-resolve: 4.2.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + + '@commitlint/rules@19.8.1': + dependencies: + '@commitlint/ensure': 19.8.1 + '@commitlint/message': 19.8.1 + '@commitlint/to-lines': 19.8.1 + '@commitlint/types': 19.8.1 + + '@commitlint/to-lines@19.8.1': {} + + '@commitlint/top-level@19.8.1': + dependencies: + find-up: 7.0.0 + + '@commitlint/types@19.8.1': + dependencies: + '@types/conventional-commits-parser': 5.0.2 + chalk: 5.6.2 + + '@defi-wonderland/natspec-smells@1.1.6(typescript@5.9.3)(zod@3.25.76)': + dependencies: + fast-glob: 3.3.2 + solc-typed-ast: 18.2.4(typescript@5.9.3)(zod@3.25.76) + yargs: 17.7.2 + transitivePeerDependencies: + - debug + - typescript + - zod + + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.2.0': + dependencies: + '@noble/hashes': 1.3.2 + + '@noble/curves@1.4.2': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/curves@1.9.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + optional: true + + '@noble/hashes@1.3.2': {} + + '@noble/hashes@1.4.0': {} + + '@noble/hashes@1.8.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + optional: true + + '@safe-global/api-kit@4.0.1(typescript@5.9.3)(zod@3.25.76)': + dependencies: + '@safe-global/protocol-kit': 6.1.2(typescript@5.9.3)(zod@3.25.76) + '@safe-global/types-kit': 3.0.0(typescript@5.9.3)(zod@3.25.76) + node-fetch: 2.7.0 + viem: 2.46.3(typescript@5.9.3)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + - zod + + '@safe-global/protocol-kit@4.1.7(typescript@5.9.3)(zod@3.25.76)': + dependencies: + '@noble/hashes': 1.8.0 + '@safe-global/safe-core-sdk-types': 5.1.0(typescript@5.9.3)(zod@3.25.76) + '@safe-global/safe-deployments': 1.37.51 + '@safe-global/safe-modules-deployments': 2.2.23 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + ethereumjs-util: 7.1.5 + ethers: 6.16.0 + semver: 7.7.4 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@safe-global/protocol-kit@6.1.2(typescript@5.9.3)(zod@3.25.76)': + dependencies: + '@safe-global/safe-deployments': 1.37.51 + '@safe-global/safe-modules-deployments': 2.2.23 + '@safe-global/types-kit': 3.0.0(typescript@5.9.3)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + semver: 7.7.4 + viem: 2.46.3(typescript@5.9.3)(zod@3.25.76) + optionalDependencies: + '@noble/curves': 1.9.7 + '@peculiar/asn1-schema': 2.6.0 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@safe-global/safe-core-sdk-types@5.1.0(typescript@5.9.3)(zod@3.25.76)': + dependencies: + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + transitivePeerDependencies: + - typescript + - zod + + '@safe-global/safe-deployments@1.37.51': + dependencies: + semver: 7.7.4 + + '@safe-global/safe-modules-deployments@2.2.23': {} + + '@safe-global/types-kit@3.0.0(typescript@5.9.3)(zod@3.25.76)': + dependencies: + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + transitivePeerDependencies: + - typescript + - zod + + '@scure/base@1.1.9': {} + + '@scure/base@1.2.6': {} + + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip32@1.7.0': + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip39@1.6.0': + dependencies: + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@solidity-parser/parser@0.19.0': {} + + '@types/bn.js@5.2.0': + dependencies: + '@types/node': 25.3.2 + + '@types/conventional-commits-parser@5.0.2': + dependencies: + '@types/node': 25.3.2 + + '@types/node@22.7.5': + dependencies: + undici-types: 6.19.8 + + '@types/node@25.3.2': + dependencies: + undici-types: 7.18.2 + + '@types/pbkdf2@3.1.2': + dependencies: + '@types/node': 25.3.2 + + '@types/secp256k1@4.0.7': + dependencies: + '@types/node': 25.3.2 + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + abitype@0.7.1(typescript@5.9.3)(zod@3.25.76): + dependencies: + typescript: 5.9.3 + optionalDependencies: + zod: 3.25.76 + + abitype@1.2.3(typescript@5.9.3)(zod@3.25.76): + optionalDependencies: + typescript: 5.9.3 + zod: 3.25.76 + + aes-js@4.0.0-beta.5: {} + + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + antlr4@4.13.2: {} + + argparse@2.0.1: {} + + array-ify@1.0.0: {} + + asn1js@3.0.7: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + optional: true + + ast-parents@0.0.1: {} + + astral-regex@2.0.0: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axios@1.13.5: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + base-x@3.0.11: + dependencies: + safe-buffer: 5.2.1 + + blakejs@1.2.1: {} + + bn.js@4.12.3: {} + + bn.js@5.2.3: {} + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brorand@1.1.0: {} + + browserify-aes@1.2.0: + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.7 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + bs58@4.0.1: + dependencies: + base-x: 3.0.11 + + bs58check@2.1.2: + dependencies: + bs58: 4.0.1 + create-hash: 1.2.0 + safe-buffer: 5.2.1 + + buffer-xor@1.0.3: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + cipher-base@1.0.7: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@5.1.1: + dependencies: + slice-ansi: 7.1.2 + string-width: 8.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + command-exists@1.2.9: {} + + commander@11.1.0: {} + + commander@12.1.0: {} + + commander@14.0.3: {} + + commander@8.3.0: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + conventional-changelog-angular@7.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@7.0.2: + dependencies: + compare-func: 2.0.0 + + conventional-commits-parser@5.0.0: + dependencies: + JSONStream: 1.3.5 + is-text-path: 2.0.0 + meow: 12.1.1 + split2: 4.2.0 + + core-util-is@1.0.3: {} + + cosmiconfig-typescript-loader@6.2.0(@types/node@25.3.2)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3): + dependencies: + '@types/node': 25.3.2 + cosmiconfig: 9.0.0(typescript@5.9.3) + jiti: 2.6.1 + typescript: 5.9.3 + + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + + cosmiconfig@9.0.0(typescript@5.9.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.9.3 + + create-hash@1.2.0: + dependencies: + cipher-base: 1.0.7 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.3 + sha.js: 2.4.12 + + create-hmac@1.1.7: + dependencies: + cipher-base: 1.0.7 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.3 + safe-buffer: 5.2.1 + sha.js: 2.4.12 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + dargs@8.1.0: {} + + decimal.js@10.6.0: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + delayed-stream@1.0.0: {} + + detect-file@1.0.0: {} + + detect-indent@7.0.2: {} + + detect-newline@4.0.1: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dotenv@16.6.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + elliptic@6.6.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + env-paths@2.2.1: {} + + environment@1.1.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + escalade@3.2.0: {} + + ethereum-cryptography@0.1.3: + dependencies: + '@types/pbkdf2': 3.1.2 + '@types/secp256k1': 4.0.7 + blakejs: 1.2.1 + browserify-aes: 1.2.0 + bs58check: 2.1.2 + create-hash: 1.2.0 + create-hmac: 1.1.7 + hash.js: 1.1.7 + keccak: 3.0.4 + pbkdf2: 3.1.5 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + scrypt-js: 3.0.1 + secp256k1: 4.0.4 + setimmediate: 1.0.5 + + ethereum-cryptography@2.2.1: + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + + ethereumjs-util@7.1.5: + dependencies: + '@types/bn.js': 5.2.0 + bn.js: 5.2.3 + create-hash: 1.2.0 + ethereum-cryptography: 0.1.3 + rlp: 2.2.7 + + ethers@6.16.0: + dependencies: + '@adraffy/ens-normalize': 1.10.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.17.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + eventemitter3@5.0.1: {} + + eventemitter3@5.0.4: {} + + evp_bytestokey@1.0.3: + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-uri@3.1.0: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@7.0.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 + + findup-sync@5.0.0: + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 4.0.8 + resolve-dir: 1.0.1 + + follow-redirects@1.15.11: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/1714bee72e286e73f76e320d110e0eaf5c4e649d: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + function-bind@1.1.2: {} + + generator-function@2.0.1: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.5.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stdin@9.0.0: {} + + get-stream@8.0.1: {} + + git-hooks-list@3.2.0: {} + + git-raw-commits@4.0.0: + dependencies: + dargs: 8.1.0 + meow: 12.1.1 + split2: 4.2.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.9 + once: 1.4.0 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + global-modules@1.0.0: + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + + global-prefix@1.0.2: + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + + globby@13.2.2: + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 4.0.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + halmos-cheatcodes#c0d8655@https://codeload.github.com/a16z/halmos-cheatcodes/tar.gz/c0d8655: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hash-base@3.1.2: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + + human-signals@5.0.0: {} + + husky@9.1.7: {} + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-meta-resolve@4.2.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + ini@4.1.1: {} + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-arrayish@0.2.1: {} + + is-callable@1.2.7: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.5.0 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-obj@2.0.0: {} + + is-plain-obj@4.1.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-stream@3.0.0: {} + + is-text-path@2.0.0: + dependencies: + text-extensions: 2.4.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-windows@1.0.2: {} + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isows@1.0.7(ws@8.18.3): + dependencies: + ws: 8.18.3 + + jiti@2.6.1: {} + + js-sha3@0.8.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsel@1.1.6: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonparse@1.3.1: {} + + keccak@3.0.4: + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.8.4 + readable-stream: 3.6.2 + + lines-and-columns@1.2.4: {} + + lint-staged@16.2.7: + dependencies: + commander: 14.0.3 + listr2: 9.0.5 + micromatch: 4.0.8 + nano-spawn: 2.0.0 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.8.2 + + listr2@9.0.5: + dependencies: + cli-truncate: 5.1.1 + colorette: 2.0.20 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash.camelcase@4.3.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.kebabcase@4.1.1: {} + + lodash.merge@4.6.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.startcase@4.4.0: {} + + lodash.truncate@4.4.2: {} + + lodash.uniq@4.5.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.23: {} + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + + math-intrinsics@1.1.0: {} + + md5.js@1.3.5: + dependencies: + hash-base: 3.1.2 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + memorystream@0.3.1: {} + + meow@12.1.1: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + nano-spawn@2.0.0: {} + + node-addon-api@2.0.2: {} + + node-addon-api@5.1.0: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-gyp-build@4.8.4: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + os-tmpdir@1.0.2: {} + + ox@0.12.4(typescript@5.9.3)(zod@3.25.76): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-passwd@1.0.0: {} + + path-exists@5.0.0: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-type@4.0.0: {} + + pbkdf2@3.1.5: + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.3 + safe-buffer: 5.2.1 + sha.js: 2.4.12 + to-buffer: 1.2.2 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + pluralize@8.0.0: {} + + possible-typed-array-names@1.1.0: {} + + prettier@2.8.8: + optional: true + + process-nextick-args@2.0.1: {} + + proxy-from-env@1.1.0: {} + + punycode@2.3.1: {} + + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + optional: true + + pvutils@1.1.5: + optional: true + + queue-microtask@1.2.3: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-dir@1.0.1: + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + ripemd160@2.0.3: + dependencies: + hash-base: 3.1.2 + inherits: 2.0.4 + + rlp@2.2.7: + dependencies: + bn.js: 5.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scrypt-js@3.0.1: {} + + secp256k1@4.0.4: + dependencies: + elliptic: 6.6.1 + node-addon-api: 5.1.0 + node-gyp-build: 4.8.4 + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + setimmediate@1.0.5: {} + + sha.js@2.4.12: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + slash@4.0.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + solc-typed-ast@18.2.4(typescript@5.9.3)(zod@3.25.76): + dependencies: + axios: 1.13.5 + commander: 12.1.0 + decimal.js: 10.6.0 + findup-sync: 5.0.0 + fs-extra: 11.3.3 + jsel: 1.1.6 + semver: 7.7.4 + solc: 0.8.25 + src-location: 1.1.0 + web3-eth-abi: 4.4.1(typescript@5.9.3)(zod@3.25.76) + transitivePeerDependencies: + - debug + - typescript + - zod + + solc@0.8.25: + dependencies: + command-exists: 1.2.9 + commander: 8.3.0 + follow-redirects: 1.15.11 + js-sha3: 0.8.0 + memorystream: 0.3.1 + semver: 5.7.2 + tmp: 0.0.33 + transitivePeerDependencies: + - debug + + solhint-community@4.0.1(typescript@5.9.3): + dependencies: + '@solidity-parser/parser': 0.19.0 + ajv: 6.14.0 + antlr4: 4.13.2 + ast-parents: 0.0.1 + chalk: 4.1.2 + commander: 11.1.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + fast-diff: 1.3.0 + glob: 8.1.0 + ignore: 5.3.2 + js-yaml: 4.1.1 + lodash: 4.17.23 + pluralize: 8.0.0 + semver: 6.3.1 + strip-ansi: 6.0.1 + table: 6.9.0 + text-table: 0.2.0 + optionalDependencies: + prettier: 2.8.8 + transitivePeerDependencies: + - typescript + + sort-object-keys@1.1.3: {} + + sort-package-json@2.10.0: + dependencies: + detect-indent: 7.0.2 + detect-newline: 4.0.1 + get-stdin: 9.0.0 + git-hooks-list: 3.2.0 + globby: 13.2.2 + is-plain-obj: 4.1.0 + semver: 7.7.4 + sort-object-keys: 1.1.3 + + split2@4.2.0: {} + + src-location@1.1.0: {} + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 + + string-width@8.2.0: + dependencies: + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-final-newline@3.0.0: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + table@6.9.0: + dependencies: + ajv: 8.18.0 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + text-extensions@2.4.0: {} + + text-table@0.2.0: {} + + through@2.3.8: {} + + tinyexec@1.0.2: {} + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + to-buffer@1.2.2: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + tslib@2.7.0: {} + + tslib@2.8.1: + optional: true + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typescript@5.9.3: {} + + undici-types@6.19.8: {} + + undici-types@7.18.2: {} + + unicorn-magic@0.1.0: {} + + universalify@2.0.1: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.2 + is-typed-array: 1.1.15 + which-typed-array: 1.1.20 + + viem@2.46.3(typescript@5.9.3)(zod@3.25.76): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + isows: 1.0.7(ws@8.18.3) + ox: 0.12.4(typescript@5.9.3)(zod@3.25.76) + ws: 8.18.3 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + web3-errors@1.3.1: + dependencies: + web3-types: 1.10.0 + + web3-eth-abi@4.4.1(typescript@5.9.3)(zod@3.25.76): + dependencies: + abitype: 0.7.1(typescript@5.9.3)(zod@3.25.76) + web3-errors: 1.3.1 + web3-types: 1.10.0 + web3-utils: 4.3.3 + web3-validator: 2.0.6 + transitivePeerDependencies: + - typescript + - zod + + web3-types@1.10.0: {} + + web3-utils@4.3.3: + dependencies: + ethereum-cryptography: 2.2.1 + eventemitter3: 5.0.4 + web3-errors: 1.3.1 + web3-types: 1.10.0 + web3-validator: 2.0.6 + + web3-validator@2.0.6: + dependencies: + ethereum-cryptography: 2.2.1 + util: 0.12.5 + web3-errors: 1.3.1 + web3-types: 1.10.0 + zod: 3.25.76 + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + ws@8.17.1: {} + + ws@8.18.3: {} + + y18n@5.0.8: {} + + yaml@2.8.2: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@1.2.2: {} + + zod@3.25.76: {} diff --git a/scripts/submit-upgrade-to-safe.mjs b/scripts/submit-upgrade-to-safe.mjs index 06950b3..7a51024 100644 --- a/scripts/submit-upgrade-to-safe.mjs +++ b/scripts/submit-upgrade-to-safe.mjs @@ -5,19 +5,34 @@ * Uses PROPOSER_PRIVATE_KEY (or PROPOSER_PK) from env. Proposer must be a Safe owner. * * Usage: - * node scripts/submit-upgrade-to-safe.mjs - * PROXY_ADMIN_ADDRESS=0x... PROXY_ADDRESS=0x... NEW_IMPLEMENTATION_ADDRESS=0x... SAFE_ADDRESS=0x... node scripts/submit-upgrade-to-safe.mjs base + * node scripts/submit-upgrade-to-safe.mjs [nonce] + * Or: pnpm run upgrade:submit-to-safe -- mainnet + * Or: pnpm run upgrade:submit-to-safe -- base 514 * - * Required env: PROPOSER_PRIVATE_KEY (or PROPOSER_PK), SAFE_ADDRESS, PROXY_ADMIN_ADDRESS, PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS, - * and _RPC (e.g. BASE_RPC for chain=base). + * Optional: SAFE_TX_NONCE or third argument sets the Safe transaction nonce (e.g. when you have + * other transactions in the queue and want this one to execute in a specific order). + * + * Loads .env from project root automatically. Required: SAFE_ADDRESS, PROXY_ADMIN_ADDRESS, + * PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS, PROPOSER_PRIVATE_KEY (or PROPOSER_PK), _RPC. */ -// Env: source .env before running, or use node -r dotenv/config -import Safe from '@safe-global/protocol-kit'; -import SafeApiKit from '@safe-global/api-kit'; +import { fileURLToPath } from 'url'; +import path from 'path'; +import { config } from 'dotenv'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +// override: true so .env wins over any MAINNET_RPC etc. already set in the shell (e.g. from another file) +config({ path: path.join(__dirname, '..', '.env'), override: true }); + +// CJS default export can appear as .default when imported from ESM +import SafeModule from '@safe-global/protocol-kit'; +import SafeApiKitModule from '@safe-global/api-kit'; import { OperationType } from '@safe-global/types-kit'; import { ethers } from 'ethers'; +const Safe = SafeModule?.default ?? SafeModule; +const SafeApiKit = SafeApiKitModule?.default ?? SafeApiKitModule; + const CHAIN_IDS = { mainnet: 1, sepolia: 11155111, @@ -49,8 +64,16 @@ function getChainId(chain) { function getRpcUrl(chain) { const key = chain.toLowerCase().replace(/-/g, '_'); const envKey = key === 'mainnet' ? 'MAINNET_RPC' : `${key.toUpperCase()}_RPC`; - const url = process.env[envKey]; + let url = (process.env[envKey] || '').trim(); + // Strip optional surrounding single/double quotes (e.g. .env: MAINNET_RPC="https://..." or 'https://...') + if ((url.startsWith('"') && url.endsWith('"')) || (url.startsWith("'") && url.endsWith("'"))) { + url = url.slice(1, -1).trim(); + } if (!url) throw new Error(`Missing ${envKey} in .env`); + if (!url.startsWith('http://') && !url.startsWith('https://')) { + const preview = url.length > 30 ? `${url.slice(0, 25)}...` : url; + throw new Error(`${envKey} must be a full RPC URL starting with https:// (e.g. https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY). Got: ${preview}`); + } return url; } @@ -69,9 +92,21 @@ function main() { if (!safeAddress || !proxyAdmin || !proxy || !newImplementation) { console.error('Usage: node scripts/submit-upgrade-to-safe.mjs '); - console.error('Required env: SAFE_ADDRESS, PROXY_ADMIN_ADDRESS, PROXY_ADDRESS, NEW_IMPLEMENTATION_ADDRESS'); - console.error('Required env: PROPOSER_PRIVATE_KEY (or PROPOSER_PK) β€” proposer must be a Safe owner'); - console.error('Required env: _RPC (e.g. BASE_RPC)'); + console.error('Required env (set in .env):'); + console.error(' SAFE_ADDRESS (your multisig address)'); + console.error(' PROXY_ADMIN_ADDRESS (ProxyAdmin contract)'); + console.error(' PROXY_ADDRESS (DonationHandler proxy to upgrade)'); + console.error(' NEW_IMPLEMENTATION_ADDRESS (from deploy:implementation)'); + console.error(' PROPOSER_PRIVATE_KEY or PROPOSER_PK (Safe owner key)'); + console.error(' SAFE_API_KEY (get at https://developer.safe.global)'); + console.error(' MAINNET_RPC (or _RPC for the chain you use)'); + console.error('Optional: SAFE_TX_NONCE or 3rd CLI arg = Safe tx nonce (for queue ordering).'); + const missing = []; + if (!safeAddress) missing.push('SAFE_ADDRESS'); + if (!proxyAdmin) missing.push('PROXY_ADMIN_ADDRESS'); + if (!proxy) missing.push('PROXY_ADDRESS'); + if (!newImplementation) missing.push('NEW_IMPLEMENTATION_ADDRESS'); + if (missing.length) console.error('Missing or empty:', missing.join(', ')); process.exit(1); } @@ -80,6 +115,13 @@ function main() { const proposerPk = getProposerPrivateKey(); const proposerAddress = new ethers.Wallet(proposerPk).address; + const nonceRaw = process.argv[3] ?? process.env.SAFE_TX_NONCE; + const nonce = nonceRaw != null && nonceRaw !== '' ? Number(nonceRaw) : undefined; + if (nonceRaw != null && nonceRaw !== '' && (Number.isNaN(nonce) || nonce < 0 || !Number.isInteger(nonce))) { + console.error('SAFE_TX_NONCE / nonce must be a non-negative integer.'); + process.exit(1); + } + // Calldata: upgrade(address proxy, address implementation) const iface = new ethers.Interface(['function upgrade(address proxy, address implementation)']); const data = iface.encodeFunctionData('upgrade', [proxy, newImplementation]); @@ -93,22 +135,39 @@ function main() { (async() => { try { - const provider = new ethers.JsonRpcProvider(rpcUrl); + // Safe SDK expects RPC URL string (HttpTransport) or EIP-1193 provider, not ethers Provider const protocolKit = await Safe.init({ - provider, + provider: rpcUrl, signer: proposerPk, safeAddress, }); + // GS013: Safe requires success || safeTxGas != 0 || gasPrice != 0. If we omit these, + // a reverted inner call causes the Safe to revert with GS013. Set safeTxGas so the + // Safe doesn't wrap the failure; use enough for Safe overhead + ProxyAdmin.upgrade. + const txOptions = { + safeTxGas: '500000', + gasPrice: '0', + }; + if (nonce !== undefined) { + txOptions.nonce = nonce; + } const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData], + options: txOptions, }); const safeTxHash = await protocolKit.getTransactionHash(safeTransaction); const signature = await protocolKit.signHash(safeTxHash); + const safeApiKey = (process.env.SAFE_API_KEY || '').trim(); + if (!safeApiKey) { + throw new Error( + 'SAFE_API_KEY is required. Get a free key at https://developer.safe.global and add SAFE_API_KEY=your_key to .env' + ); + } const apiKit = new SafeApiKit({ chainId, - ...(process.env.SAFE_API_KEY && { apiKey: process.env.SAFE_API_KEY }), + apiKey: safeApiKey, }); await apiKit.proposeTransaction({ @@ -121,10 +180,21 @@ function main() { const slug = SAFE_APP_CHAIN_SLUG[chain ? chain.toLowerCase() : 'mainnet'] || 'eth'; console.log('Proposal submitted to Safe Transaction Service.'); + if (nonce !== undefined) console.log('Nonce used:', nonce); console.log('Safe tx hash:', safeTxHash); console.log('View in Safe:', `https://app.safe.global/transactions/queue?safe=${slug}:${safeAddress}`); } catch (err) { console.error('Propose failed:', err.message || err); + // Log API response body when present (e.g. 422 Unprocessable Content) + const body = err?.response?.data ?? err?.data ?? err?.body; + if (body && typeof body === 'object') { + console.error('API response:', JSON.stringify(body, null, 2)); + } else if (body && typeof body === 'string') { + console.error('API response:', body); + } + if (err?.message?.includes('Unprocessable') || err?.message?.includes('422')) { + console.error('\nCommon causes: Safe at SAFE_ADDRESS may not exist on this chain, or proposer is not an owner of that Safe on this chain. Use the correct Safe address for Polygon.'); + } process.exit(1); } })(); From 347c4a42a948d47c93ad1debe8a6b23142072489 Mon Sep 17 00:00:00 2001 From: ali Date: Wed, 11 Mar 2026 03:48:38 +0330 Subject: [PATCH 08/14] feat: streamline upgrade process and enhance documentation - Replaced upgrade scripts in package.json with a new direct upgrade command. - Expanded MULTISIG_UPGRADE_GUIDE.md to clarify upgrade flows for both multisig and EOA owners. - Updated UpgradeDonationHandler script to utilize pre-deployed implementation addresses. - Improved clarity in upgrade instructions and environment variable requirements. --- docs/MULTISIG_UPGRADE_GUIDE.md | 71 ++++++++++++++++++++++----- package.json | 4 +- script/UpgradeDonationHandler.s.sol | 15 +++--- scripts/upgrade-direct.sh | 75 +++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 25 deletions(-) create mode 100755 scripts/upgrade-direct.sh diff --git a/docs/MULTISIG_UPGRADE_GUIDE.md b/docs/MULTISIG_UPGRADE_GUIDE.md index 2c9bd19..91b2b26 100644 --- a/docs/MULTISIG_UPGRADE_GUIDE.md +++ b/docs/MULTISIG_UPGRADE_GUIDE.md @@ -1,10 +1,53 @@ -# DonationHandler upgrade β€” guide for multisig signers +# DonationHandler upgrade guide -This guide is for signers of the **ProxyAdmin** multisig. It explains how to run a single transaction to upgrade the DonationHandler to a new implementation. +This guide covers upgrading the DonationHandler proxy to a new implementation. **Both flows use the same addresses:** deploy the new implementation once with `yarn deploy:implementation `, then either propose a Safe transaction (multisig owner) or run the direct upgrade (EOA owner). --- -## Steps to propose the transaction +## Which flow to use + +| ProxyAdmin owner on chain | Flow | Command | +|---------------------------|------|--------| +| **Safe (multisig)** | Submit upgrade to Safe; signers confirm and execute | `yarn upgrade:submit-to-safe -- ` | +| **Your EOA** | Direct upgrade: you sign and broadcast the upgrade tx | `yarn upgrade:direct -- ` | + +Same env for both: `PROXY_ADDRESS`, `PROXY_ADMIN_ADDRESS`, `NEW_IMPLEMENTATION_ADDRESS` (from `yarn deploy:implementation `), and `_RPC`. For Safe you also need `SAFE_ADDRESS`, `PROPOSER_PRIVATE_KEY`, `SAFE_API_KEY`. For direct you need `PRIVATE_KEY` (the EOA that owns ProxyAdmin). + +--- + +## Direct upgrade (EOA owner) + +When the ProxyAdmin owner is your EOA (not a Safe) on that chain: + +1. **Deploy the new implementation** (once per chain): + ```bash + yarn deploy:implementation + ``` + Example: `yarn deploy:implementation polygon`. Note the deployed implementation address. + +2. **Set in `.env`:** + - `PROXY_ADDRESS` = DonationHandler proxy + - `PROXY_ADMIN_ADDRESS` = ProxyAdmin contract + - `NEW_IMPLEMENTATION_ADDRESS` = address from step 1 + - `PRIVATE_KEY` = private key of the EOA that **owns** the ProxyAdmin + - `_RPC` = RPC URL (e.g. `POLYGON_RPC`, `BASE_RPC`) + +3. **Simulate (optional):** + ```bash + yarn upgrade:direct -- polygon --simulate + ``` + +4. **Run the upgrade:** + ```bash + yarn upgrade:direct -- polygon + ``` + Use the correct chain instead of `polygon` if needed (e.g. `base`, `mainnet`, `sepolia`). + +The script calls `ProxyAdmin.upgradeAndCall(proxy, NEW_IMPLEMENTATION_ADDRESS, '')`; it does **not** deploy a new implementation. + +--- + +## Multisig (Safe) β€” steps to propose the transaction Choose one of two ways: **A) Submit from your machine** (script posts to Safe) or **B) Generate payload** then create the tx in the Safe UI. @@ -101,8 +144,8 @@ The script will create the upgrade transaction, sign it with the proposer key, a ## What you’re doing - The **DonationHandler** logic lives behind an upgradeable proxy. -- You will call **ProxyAdmin.upgrade(proxy, newImplementation)** so the proxy starts using the new implementation. -- Only the ProxyAdmin owner (your multisig) can do this. One transaction, no code β€” just the new implementation address. +- You call **ProxyAdmin.upgrade(proxy, newImplementation)** (or `upgradeAndCall` with empty data) so the proxy points to the new implementation. +- Only the ProxyAdmin **owner** can do this (multisig or EOA). The new implementation is deployed once with `yarn deploy:implementation `; the upgrade step only updates the proxy to use that address. --- @@ -110,10 +153,10 @@ The script will create the upgrade transaction, sign it with the proposer key, a | Item | Description | |------|-------------| -| **ProxyAdmin address** | The contract your multisig owns (e.g. `0x...`) | +| **ProxyAdmin address** | The contract whose owner will run the upgrade (multisig or your EOA) | | **Proxy address** | The DonationHandler proxy to upgrade (e.g. `0x...`) | -| **New implementation address** | The newly deployed implementation (e.g. `0x...`) | -| **Network** | The chain where the proxy lives (e.g. Ethereum, Base, Celo) | +| **New implementation address** | From `yarn deploy:implementation ` β€” deploy once, then use in Safe or direct upgrade | +| **Network** | The chain where the proxy lives (e.g. Ethereum, Base, Polygon, Celo) | --- @@ -171,22 +214,24 @@ Use **Contract interaction** with **Custom data**: --- -## Checklist for proposer / first signer +## Checklist for multisig proposer / first signer - [ ] Confirm **proxy**, **ProxyAdmin**, and **new implementation** addresses and **network** with the team. - [ ] Confirm the new implementation is **verified** on the block explorer for that network. - [ ] Create the Safe transaction as above and share the link or batch ID for other signers to sign. +For **direct upgrade** (EOA owner), after deploying the implementation and setting env, run `yarn upgrade:direct -- --simulate` then `yarn upgrade:direct -- `. + --- ## Quick reference | Role | Address type | Example use | |------|--------------|-------------| -| **ProxyAdmin** | Contract you call | β€œTo” in Safe = ProxyAdmin | +| **ProxyAdmin** | Contract you call | β€œTo” in Safe; target of upgrade script | | **Proxy** | First argument of `upgrade` | DonationHandler proxy | -| **New implementation** | Second argument of `upgrade` | New implementation address | +| **New implementation** | Second argument of `upgrade` | From `yarn deploy:implementation ` | -**Function:** `upgrade(address proxy, address implementation)` +**Function:** `upgrade(address proxy, address implementation)` (or `upgradeAndCall(proxy, implementation, '')`) **Value:** 0 -**Only the ProxyAdmin owner (your multisig) can call this.** +**Only the ProxyAdmin owner (multisig or EOA) can call this.** diff --git a/package.json b/package.json index 16ab8b5..0cc7107 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,8 @@ "test:symbolic": "halmos", "test:unit": "forge test --match-contract Unit -vvv", "test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit", + "upgrade:direct": "./scripts/upgrade-direct.sh", "upgrade:generate-payload": "./scripts/generate-upgrade-payload.sh", - "upgrade:mainnet": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify -vvvv'", - "upgrade:mainnet:simulate": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --fork-url $MAINNET_RPC -vvvv'", - "upgrade:sepolia": "bash -c 'source .env && forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", "upgrade:submit-to-safe": "node scripts/submit-upgrade-to-safe.mjs" }, "lint-staged": { diff --git a/script/UpgradeDonationHandler.s.sol b/script/UpgradeDonationHandler.s.sol index a917052..c3baf64 100644 --- a/script/UpgradeDonationHandler.s.sol +++ b/script/UpgradeDonationHandler.s.sol @@ -1,39 +1,36 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.22; -import {DonationHandler} from '../src/contracts/DonationHandler.sol'; import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; import {ITransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; import {Script} from 'forge-std/Script.sol'; import {console} from 'forge-std/console.sol'; contract UpgradeDonationHandler is Script { - /// @notice Upgrade existing proxy. Set PROXY_ADDRESS and PROXY_ADMIN_ADDRESS in .env (or pass via CLI). + /// @notice Upgrade existing proxy to a pre-deployed implementation. + /// Set PROXY_ADDRESS, PROXY_ADMIN_ADDRESS, NEW_IMPLEMENTATION_ADDRESS in .env (deploy impl via deploy:implementation first). function run() external { uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); address proxyAddress = vm.envAddress('PROXY_ADDRESS'); address proxyAdminAddress = vm.envAddress('PROXY_ADMIN_ADDRESS'); + address newImplementation = vm.envAddress('NEW_IMPLEMENTATION_ADDRESS'); console.log('=== Upgrading DonationHandler ==='); console.log('Proxy Address:', proxyAddress); console.log('ProxyAdmin Address:', proxyAdminAddress); + console.log('New Implementation:', newImplementation); vm.startBroadcast(deployerPrivateKey); - // Step 1: Deploy new implementation - DonationHandler newImplementation = new DonationHandler(); - console.log('New Implementation deployed to:', address(newImplementation)); - - // Step 2: Upgrade the proxy to point to new implementation ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress); proxyAdmin.upgradeAndCall( ITransparentUpgradeableProxy(proxyAddress), - address(newImplementation), + newImplementation, '' // No initialization data needed for upgrade ); console.log('Proxy upgraded successfully!'); - console.log('Proxy now points to implementation:', address(newImplementation)); + console.log('Proxy now points to implementation:', newImplementation); vm.stopBroadcast(); } diff --git a/scripts/upgrade-direct.sh b/scripts/upgrade-direct.sh new file mode 100755 index 0000000..a2c626c --- /dev/null +++ b/scripts/upgrade-direct.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -e + +# Direct upgrade: call ProxyAdmin.upgradeAndCall with an already-deployed implementation. +# Use when the ProxyAdmin owner is an EOA (your PRIVATE_KEY), not a Safe. +# +# Usage: ./scripts/upgrade-direct.sh [--simulate] +# Example: yarn upgrade:direct polygon +# yarn upgrade:direct polygon --simulate +# +# Chain is first argument. RPC from env: _RPC (e.g. POLYGON_RPC, BASE_RPC). +# Required env: PRIVATE_KEY (EOA that owns ProxyAdmin), PROXY_ADDRESS, PROXY_ADMIN_ADDRESS, +# NEW_IMPLEMENTATION_ADDRESS (from yarn deploy:implementation ). + +CHAIN="${1:?Usage: upgrade-direct.sh [--simulate] (e.g. polygon, base, mainnet, sepolia)}" +SIMULATE="" +if [[ "${2:-}" == "--simulate" ]]; then + SIMULATE="1" +fi + +cd "$(dirname "$0")/.." +source .env + +# Derive RPC env var from chain name: base -> BASE_RPC, mainnet -> MAINNET_RPC +RPC_SUFFIX=$(echo "$CHAIN" | tr '[:lower:]' '[:upper:]' | tr '-' '_') +RPC_VAR="${RPC_SUFFIX}_RPC" + +if [[ -z "${!RPC_VAR}" ]]; then + echo "Error: $RPC_VAR is not set in .env" + exit 1 +fi + +if [[ -z "${PRIVATE_KEY:-}" ]]; then + echo "Error: PRIVATE_KEY is not set in .env (must be the EOA that owns ProxyAdmin)" + exit 1 +fi + +if [[ -z "${PROXY_ADDRESS:-}" ]]; then + echo "Error: PROXY_ADDRESS is not set in .env" + exit 1 +fi + +if [[ -z "${PROXY_ADMIN_ADDRESS:-}" ]]; then + echo "Error: PROXY_ADMIN_ADDRESS is not set in .env" + exit 1 +fi + +if [[ -z "${NEW_IMPLEMENTATION_ADDRESS:-}" ]]; then + echo "Error: NEW_IMPLEMENTATION_ADDRESS is not set in .env (deploy with: yarn deploy:implementation )" + exit 1 +fi + +# Chains that don't support EIP-1559 need legacy transactions +LEGACY_CHAINS="celo gnosis" +LEGACY_FLAG="" +if [[ " $LEGACY_CHAINS " == *" $CHAIN "* ]]; then + LEGACY_FLAG="--legacy" +fi + +if [[ -n "$SIMULATE" ]]; then + echo "Simulating upgrade on $CHAIN (no broadcast)..." + forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --fork-url "${!RPC_VAR}" \ + --chain "$CHAIN" \ + $LEGACY_FLAG \ + -vvvv +else + echo "Running direct upgrade on $CHAIN..." + forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url "${!RPC_VAR}" \ + --broadcast \ + --chain "$CHAIN" \ + $LEGACY_FLAG \ + -vvvv +fi From 64802715757183849dae118f6c61dc3609b6d72a Mon Sep 17 00:00:00 2001 From: ali Date: Mon, 23 Mar 2026 01:03:09 +0330 Subject: [PATCH 09/14] feat: update upgrade process to use upgradeAndCall - Update PRODUCTION_UPGRADE.md and MULTISIG_UPGRADE_GUIDE.md for `upgradeAndCall`. - Generate Safe calldata with empty `data` so upgrades do not trigger initialization. - Clarify upgrade instructions and warn against calling `initialize()` during upgrades. --- PRODUCTION_UPGRADE.md | 8 +- docs/MULTISIG_UPGRADE_GUIDE.md | 32 +- scripts/generate-upgrade-payload.sh | 21 +- scripts/submit-upgrade-to-safe.mjs | 40 +- yarn.lock | 798 +++++++++++++++++++++++++++- 5 files changed, 856 insertions(+), 43 deletions(-) diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md index bff83d3..5b178f9 100644 --- a/PRODUCTION_UPGRADE.md +++ b/PRODUCTION_UPGRADE.md @@ -42,13 +42,17 @@ The script will output the new implementation address. Save it (e.g. `export NEW Send the **implementation address** to the ProxyAdmin owner. They should run: ```solidity -proxyAdmin.upgrade(proxy, NEW_IMPLEMENTATION_ADDRESS); +proxyAdmin.upgradeAndCall(proxy, NEW_IMPLEMENTATION_ADDRESS, ''); ``` Or via `cast`: ```bash -cast send $PROXY_ADMIN_ADDRESS "upgrade(address,address)" $PROXY_ADDRESS $NEW_IMPLEMENTATION_ADDRESS \ +cast send $PROXY_ADMIN_ADDRESS \ + "upgradeAndCall(address,address,bytes)" \ + $PROXY_ADDRESS \ + $NEW_IMPLEMENTATION_ADDRESS \ + 0x \ --rpc-url $MAINNET_RPC --private-key $OWNER_PRIVATE_KEY ``` diff --git a/docs/MULTISIG_UPGRADE_GUIDE.md b/docs/MULTISIG_UPGRADE_GUIDE.md index 91b2b26..a5ee8ff 100644 --- a/docs/MULTISIG_UPGRADE_GUIDE.md +++ b/docs/MULTISIG_UPGRADE_GUIDE.md @@ -15,6 +15,21 @@ Same env for both: `PROXY_ADDRESS`, `PROXY_ADMIN_ADDRESS`, `NEW_IMPLEMENTATION_A --- +## Upgrade safety: do not call `initialize()` on upgrade + +The scripts in this repo **only** switch the proxy to the new implementation; they **do not** pass any calldata to run `initialize()` (or any other function) on the new implementation. + +- **Safe flow:** uses `ProxyAdmin.upgradeAndCall(proxy, implementation, '0x')` (empty data). +- **Direct flow:** uses `ProxyAdmin.upgradeAndCall(proxy, implementation, '')` (empty data). + +**Why this matters (TransparentUpgradeableProxy + ProxyAdmin):** + +If you upgraded with `upgradeAndCall(proxy, implementation, initialize())`, the call path would be Safe β†’ ProxyAdmin β†’ proxy β†’ `implementation.initialize()`. Inside `initialize()`, **`msg.sender` is the ProxyAdmin**, not the Safe. So `__Ownable_init(msg.sender)` would set **owner = ProxyAdmin**. That would leave the proxy in a bad state: the ProxyAdmin cannot call `onlyOwner` functions through the proxy (the transparent proxy blocks admin from implementation calls), and the Safe would no longer be the owner. In addition, if the proxy was already initialized, calling `initialize()` again would revert with `InvalidInitialization()`. + +**If the new implementation needs one-time setup or migration**, add a **new** function that uses `reinitializer(2)` (or the right version), pass the **intended owner explicitly** (e.g. your Safe address), and call it in a **separate** transaction after the upgrade β€” not as the upgrade payload. Do not rely on `msg.sender` for ownership in any upgrade-time call. + +--- + ## Direct upgrade (EOA owner) When the ProxyAdmin owner is your EOA (not a Safe) on that chain: @@ -104,7 +119,7 @@ Choose one of two ways: **A) Submit from your machine** (script posts to Safe) o - Open the printed Safe link (or [app.safe.global](https://app.safe.global)). - **New transaction** β†’ **Contract interaction** (or **Apps** β†’ **Transaction Builder**). - **To:** paste `PROXY_ADMIN_ADDRESS`. - - **Data:** paste the hex **Data (calldata)** from the script output, or use the function `upgrade(address,address)` with `proxy` = `PROXY_ADDRESS` and `implementation` = `NEW_IMPLEMENTATION_ADDRESS`. + - **Data:** paste the hex **Data (calldata)** from the script output, or use the function `upgradeAndCall(address,address,bytes)` with `proxy` = `PROXY_ADDRESS`, `implementation` = `NEW_IMPLEMENTATION_ADDRESS`, and `data` = `0x`. - **Value:** 0. - **Create transaction** so other signers can sign and execute. @@ -144,7 +159,7 @@ The script will create the upgrade transaction, sign it with the proposer key, a ## What you’re doing - The **DonationHandler** logic lives behind an upgradeable proxy. -- You call **ProxyAdmin.upgrade(proxy, newImplementation)** (or `upgradeAndCall` with empty data) so the proxy points to the new implementation. +- You call **ProxyAdmin.upgradeAndCall(proxy, newImplementation, '0x')** so the proxy points to the new implementation without running `initialize()`. - Only the ProxyAdmin **owner** can do this (multisig or EOA). The new implementation is deployed once with `yarn deploy:implementation `; the upgrade step only updates the proxy to use that address. --- @@ -184,7 +199,7 @@ The script will create the upgrade transaction, sign it with the proposer key, a --- -## If the Safe UI doesn’t show `upgrade` +## If the Safe UI doesn’t show `upgradeAndCall` Use **Contract interaction** with **Custom data**: @@ -192,17 +207,16 @@ Use **Contract interaction** with **Custom data**: - **Data (hex):** use the ABI-encoded call: ```text - upgrade(address,address) + upgradeAndCall(address,address,bytes) ``` Encoded with: - - **Selector:** `0x99...` (first 4 bytes of `keccak256("upgrade(address,address)")`). - You can get the exact calldata from a block explorer (e.g. Etherscan) by going to the ProxyAdmin contract β†’ **Write** β†’ **upgrade** and encoding the two addresses, or by using a small script/tool that encodes the call. + - Encode the call with `proxy`, `implementation`, and empty `data = 0x`. + You can get the exact calldata from a block explorer (e.g. Etherscan) by going to the ProxyAdmin contract β†’ **Write** β†’ **upgradeAndCall** and encoding the values, or by using a small script/tool that encodes the call. Or use an online ABI encoder: - - Function: `upgrade(address proxy, address implementation)` - - Arguments: `[ , ]` - - Prepend the 4-byte selector: `0x99...` (look up `upgrade(address,address)` selector). + - Function: `upgradeAndCall(address proxy, address implementation, bytes data)` + - Arguments: `[ , , 0x ]` --- diff --git a/scripts/generate-upgrade-payload.sh b/scripts/generate-upgrade-payload.sh index b2c9b47..2c6705e 100755 --- a/scripts/generate-upgrade-payload.sh +++ b/scripts/generate-upgrade-payload.sh @@ -33,8 +33,9 @@ case "$CHAIN" in celo) SAFE_CHAIN_SLUG="celo" ;; esac -# Build calldata: upgrade(address proxy, address implementation) -CALLDATA=$(cast calldata "upgrade(address,address)" "$PROXY" "$NEW_IMPL") +# Build calldata: upgradeAndCall(address proxy, address implementation, bytes data) +# Use empty bytes so the upgrade only switches implementation and does not run initialize(). +CALLDATA=$(cast calldata "upgradeAndCall(address,address,bytes)" "$PROXY" "$NEW_IMPL" "0x") echo "" echo "==============================================" @@ -45,9 +46,10 @@ echo " To (Contract): $PROXY_ADMIN" echo " Value: 0" echo " Data (calldata): $CALLDATA" echo "" -echo " Function: upgrade(address proxy, address implementation)" +echo " Function: upgradeAndCall(address proxy, address implementation, bytes data)" echo " proxy: $PROXY" echo " implementation: $NEW_IMPL" +echo " data: 0x" echo "" echo "==============================================" echo " How to propose in Safe" @@ -61,9 +63,10 @@ else fi echo " 2. New transaction β†’ Contract interaction" echo " 3. Contract address: $PROXY_ADMIN" -echo " 4. Use ABI: upgrade(address,address) with:" +echo " 4. Use ABI: upgradeAndCall(address,address,bytes) with:" echo " proxy = $PROXY" echo " implementation = $NEW_IMPL" +echo " data = 0x" echo " 5. Or paste Raw data (hex): $CALLDATA" echo " 6. Value: 0 β†’ Create transaction" echo "" @@ -76,7 +79,7 @@ cat > "$OUTPUT_JSON" << EOF "chainId": "$CHAIN", "meta": { "name": "DonationHandler upgrade", - "description": "ProxyAdmin.upgrade(proxy, implementation)" + "description": "ProxyAdmin.upgradeAndCall(proxy, implementation, 0x)" }, "transactions": [ { @@ -86,14 +89,16 @@ cat > "$OUTPUT_JSON" << EOF "contractMethod": { "inputs": [ { "name": "proxy", "type": "address" }, - { "name": "implementation", "type": "address" } + { "name": "implementation", "type": "address" }, + { "name": "data", "type": "bytes" } ], - "name": "upgrade", + "name": "upgradeAndCall", "payable": false }, "contractInputsValues": { "proxy": "$PROXY", - "implementation": "$NEW_IMPL" + "implementation": "$NEW_IMPL", + "data": "0x" } } ] diff --git a/scripts/submit-upgrade-to-safe.mjs b/scripts/submit-upgrade-to-safe.mjs index 7a51024..67bf054 100644 --- a/scripts/submit-upgrade-to-safe.mjs +++ b/scripts/submit-upgrade-to-safe.mjs @@ -20,7 +20,8 @@ import { fileURLToPath } from 'url'; import path from 'path'; import { config } from 'dotenv'; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const __dirname = path.dirname(fileURLToPath( + import.meta.url)); // override: true so .env wins over any MAINNET_RPC etc. already set in the shell (e.g. from another file) config({ path: path.join(__dirname, '..', '.env'), override: true }); @@ -30,8 +31,8 @@ import SafeApiKitModule from '@safe-global/api-kit'; import { OperationType } from '@safe-global/types-kit'; import { ethers } from 'ethers'; -const Safe = SafeModule?.default ?? SafeModule; -const SafeApiKit = SafeApiKitModule?.default ?? SafeApiKitModule; +const Safe = (SafeModule && SafeModule.default) ? SafeModule.default : SafeModule; +const SafeApiKit = (SafeApiKitModule && SafeApiKitModule.default) ? SafeApiKitModule.default : SafeApiKitModule; const CHAIN_IDS = { mainnet: 1, @@ -115,16 +116,19 @@ function main() { const proposerPk = getProposerPrivateKey(); const proposerAddress = new ethers.Wallet(proposerPk).address; - const nonceRaw = process.argv[3] ?? process.env.SAFE_TX_NONCE; + const nonceRaw = process.argv[3] !== undefined ? process.argv[3] : process.env.SAFE_TX_NONCE; const nonce = nonceRaw != null && nonceRaw !== '' ? Number(nonceRaw) : undefined; if (nonceRaw != null && nonceRaw !== '' && (Number.isNaN(nonce) || nonce < 0 || !Number.isInteger(nonce))) { console.error('SAFE_TX_NONCE / nonce must be a non-negative integer.'); process.exit(1); } - // Calldata: upgrade(address proxy, address implementation) - const iface = new ethers.Interface(['function upgrade(address proxy, address implementation)']); - const data = iface.encodeFunctionData('upgrade', [proxy, newImplementation]); + // Calldata: upgradeAndCall(address proxy, address implementation, bytes data) + // Use empty bytes so the upgrade only switches implementation and does not run initialize(). + const iface = new ethers.Interface([ + 'function upgradeAndCall(address proxy, address implementation, bytes data)', + ]); + const data = iface.encodeFunctionData('upgradeAndCall', [proxy, newImplementation, '0x']); const safeTransactionData = { to: proxyAdmin, @@ -135,20 +139,14 @@ function main() { (async() => { try { - // Safe SDK expects RPC URL string (HttpTransport) or EIP-1193 provider, not ethers Provider const protocolKit = await Safe.init({ provider: rpcUrl, signer: proposerPk, safeAddress, }); - // GS013: Safe requires success || safeTxGas != 0 || gasPrice != 0. If we omit these, - // a reverted inner call causes the Safe to revert with GS013. Set safeTxGas so the - // Safe doesn't wrap the failure; use enough for Safe overhead + ProxyAdmin.upgrade. - const txOptions = { - safeTxGas: '500000', - gasPrice: '0', - }; + const txOptions = {}; + if (nonce !== undefined) { txOptions.nonce = nonce; } @@ -186,13 +184,19 @@ function main() { } catch (err) { console.error('Propose failed:', err.message || err); // Log API response body when present (e.g. 422 Unprocessable Content) - const body = err?.response?.data ?? err?.data ?? err?.body; + const body = err && err.response && err.response.data ? + err.response.data : + err && err.data ? + err.data : + err && err.body ? + err.body : + undefined; if (body && typeof body === 'object') { console.error('API response:', JSON.stringify(body, null, 2)); } else if (body && typeof body === 'string') { console.error('API response:', body); } - if (err?.message?.includes('Unprocessable') || err?.message?.includes('422')) { + if (err && err.message && (err.message.includes('Unprocessable') || err.message.includes('422'))) { console.error('\nCommon causes: Safe at SAFE_ADDRESS may not exist on this chain, or proposer is not an owner of that Safe on this chain. Use the correct Safe address for Polygon.'); } process.exit(1); @@ -200,4 +204,4 @@ function main() { })(); } -main(); +main(); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 5289b10..02ececa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,16 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + +"@adraffy/ens-normalize@^1.11.0": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz#6c2d657d4b2dfb37f8ea811dcb3e60843d4ac24a" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== + "@babel/code-frame@^7.0.0": version "7.24.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" @@ -190,6 +200,18 @@ solc-typed-ast "18.2.4" yargs "17.7.2" +"@noble/ciphers@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.3.0.tgz#f64b8ff886c240e644e5573c097f86e5b43676dc" + integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== + +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/curves@1.3.0", "@noble/curves@~1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" @@ -197,11 +219,35 @@ dependencies: "@noble/hashes" "1.3.3" +"@noble/curves@1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.1.tgz#9654a0bc6c13420ae252ddcf975eaf0f58f0a35c" + integrity sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/curves@^1.6.0", "@noble/curves@~1.9.0": + version "1.9.7" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.7.tgz#79d04b4758a43e4bca2cbdc62e7771352fa6b951" + integrity sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/hashes@1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" + integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== + "@noble/hashes@1.3.3", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== +"@noble/hashes@1.8.0", "@noble/hashes@^1.3.3", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -223,11 +269,90 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@peculiar/asn1-schema@^2.3.13": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz#0dca1601d5b0fed2a72fed7a5f1d0d7dbe3a6f82" + integrity sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg== + dependencies: + asn1js "^3.0.6" + pvtsutils "^1.3.6" + tslib "^2.8.1" + +"@safe-global/api-kit@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@safe-global/api-kit/-/api-kit-4.0.1.tgz#91414e19377f985ac30f03fd0508a11e70d867b3" + integrity sha512-pNtDLgMHlCSr4Hwwe6jsnvMheAu2SZCTqjYlnNe4cKH2pSKINVRTiILoeJ0wOpixrMCH4NlgJ+9N3QruRNcCpQ== + dependencies: + "@safe-global/protocol-kit" "^6.1.2" + "@safe-global/types-kit" "^3.0.0" + node-fetch "^2.7.0" + viem "^2.21.8" + +"@safe-global/protocol-kit@^4.0.0": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-4.1.7.tgz#b0b93c894a783aee2daaef71afd9cdbcc5321f7c" + integrity sha512-4VMqbezB91JasxhOB2HhRjsCeuxBMnPdUMXh5eKEs59xE86Ys2GhQ7+xk78qaB9SKUe74wKaQAeKE+hC7nHffA== + dependencies: + "@noble/hashes" "^1.3.3" + "@safe-global/safe-core-sdk-types" "^5.1.0" + "@safe-global/safe-deployments" "^1.37.31" + "@safe-global/safe-modules-deployments" "^2.2.1" + abitype "^1.0.2" + ethereumjs-util "^7.1.5" + ethers "^6.13.1" + semver "^7.6.2" + +"@safe-global/protocol-kit@^6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-6.1.2.tgz#6cafd55aaf119998b794ff3a0cdaa2556ba2374c" + integrity sha512-cTpPdUAS2AMfGCkD1T601rQNjT0rtMQLA2TH7L/C+iFPAC6WrrDFop2B9lzeHjczlnVzrRpfFe4cL1bLrJ9NZw== + dependencies: + "@safe-global/safe-deployments" "^1.37.49" + "@safe-global/safe-modules-deployments" "^2.2.21" + "@safe-global/types-kit" "^3.0.0" + abitype "^1.0.2" + semver "^7.7.2" + viem "^2.21.8" + optionalDependencies: + "@noble/curves" "^1.6.0" + "@peculiar/asn1-schema" "^2.3.13" + +"@safe-global/safe-core-sdk-types@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk-types/-/safe-core-sdk-types-5.1.0.tgz#af8d877b9af231242d023c7182f78ff4223bc3f4" + integrity sha512-UzXR4zWmVzux25FcIm4H049QhZZpVpIBL5HE+V0p5gHpArZROL+t24fZmsKUf403CtBxIJM5zZSVQL0nFJi+IQ== + dependencies: + abitype "^1.0.2" + +"@safe-global/safe-deployments@^1.37.31", "@safe-global/safe-deployments@^1.37.49": + version "1.37.53" + resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.53.tgz#b3bb1c39dae00d0c6e57726833da34eb3ef78311" + integrity sha512-3XihirwKqcCi6jsipCiW3lYXra9i4pC9nlhHTdUyi7Yx38nBYIkXeLZN2Nmf2UPcQBeHGnW1T3DgzY4VnuF/FQ== + dependencies: + semver "^7.6.2" + +"@safe-global/safe-modules-deployments@^2.2.1", "@safe-global/safe-modules-deployments@^2.2.21": + version "2.2.25" + resolved "https://registry.yarnpkg.com/@safe-global/safe-modules-deployments/-/safe-modules-deployments-2.2.25.tgz#d0942c5d4f854a7221bcbf82bc13e15269c6822a" + integrity sha512-KjgenKhBRyFHEfo8xlBgNzKAy25vrmGyCGZwTjIuA81yOSRJRe85GE5Yfg/FBKeeyHqR2dD1WPZr6c2Uqd6C/g== + +"@safe-global/types-kit@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@safe-global/types-kit/-/types-kit-3.0.0.tgz#b35826af0e417fa02a540b874c109b5ddb5ed086" + integrity sha512-AZWIlR5MguDPdGiOj7BB4JQPY2afqmWQww1mu8m8Oi16HHBW99G01kFOu4NEHBwEU1cgwWOMY19hsI5KyL4W2w== + dependencies: + abitype "^1.0.2" + "@scure/base@~1.1.4": version "1.1.6" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== +"@scure/base@~1.2.5": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.6.tgz#ca917184b8231394dd8847509c67a0be522e59f6" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== + "@scure/bip32@1.3.3": version "1.3.3" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.3.tgz#a9624991dc8767087c57999a5d79488f48eae6c8" @@ -237,6 +362,15 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.4" +"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.7.0.tgz#b8683bab172369f988f1589640e53c4606984219" + integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== + dependencies: + "@noble/curves" "~1.9.0" + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + "@scure/bip39@1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.2.tgz#f3426813f4ced11a47489cbcf7294aa963966527" @@ -245,11 +379,26 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.4" +"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.6.0.tgz#475970ace440d7be87a6086cbee77cb8f1a684f9" + integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== + dependencies: + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + "@solidity-parser/parser@^0.19.0": version "0.19.0" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.19.0.tgz#37a8983b2725af9b14ff8c4a475fa0e98d773c3f" integrity sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA== +"@types/bn.js@^5.1.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.2.0.tgz#4349b9710e98f9ab3cdc50f1c5e4dcbd8ef29c80" + integrity sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q== + dependencies: + "@types/node" "*" + "@types/conventional-commits-parser@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#8c9d23e0b415b24b91626d07017303755d542dc8" @@ -264,6 +413,27 @@ dependencies: undici-types "~5.26.4" +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + +"@types/pbkdf2@^3.0.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.2.tgz#2dc43808e9985a2c69ff02e2d2027bd4fe33e8dc" + integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== + dependencies: + "@types/node" "*" + +"@types/secp256k1@^4.0.1": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.7.tgz#534c9814eb80964962108ad45d549d1555c75fa0" + integrity sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw== + dependencies: + "@types/node" "*" + JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -277,6 +447,16 @@ abitype@0.7.1: resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.7.1.tgz#16db20abe67de80f6183cf75f3de1ff86453b745" integrity sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ== +abitype@1.2.3, abitype@^1.0.2, abitype@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" + integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg== + +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -346,6 +526,15 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== +asn1js@^3.0.6: + version "3.0.7" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-3.0.7.tgz#15f1f2f59e60f80d5b43ef14047a294a969f824f" + integrity sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ== + dependencies: + pvtsutils "^1.3.6" + pvutils "^1.1.3" + tslib "^2.8.1" + ast-parents@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" @@ -382,6 +571,28 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-x@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.11.tgz#40d80e2a1aeacba29792ccc6c5354806421287ff" + integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== + dependencies: + safe-buffer "^5.0.1" + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@^4.11.9: + version "4.12.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.3.tgz#2cc2c679188eb35b006f2d0d4710bed8437a769e" + integrity sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g== + +bn.js@^5.1.2, bn.js@^5.2.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.3.tgz#16a9e409616b23fef3ccbedb8d42f13bff80295e" + integrity sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w== + brace-expansion@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" @@ -396,6 +607,52 @@ braces@^3.0.2: dependencies: fill-range "^7.1.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + 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" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.2, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" @@ -407,6 +664,24 @@ call-bind@^1.0.2, call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" +call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -434,6 +709,15 @@ chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.7" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.7.tgz#bd094bfef42634ccfd9e13b9fc73274997111e39" + integrity sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + to-buffer "^1.2.2" + cli-cursor@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-4.0.0.tgz#3cecfe3734bf4fe02a8361cbdc0f6fe28c6a57ea" @@ -546,6 +830,11 @@ conventional-commits-parser@^5.0.0: meow "^12.0.1" split2 "^4.0.0" +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + cosmiconfig-typescript-loader@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz#0d3becfe022a871f7275ceb2397d692e06045dc8" @@ -573,6 +862,29 @@ cosmiconfig@^9.0.0: js-yaml "^4.1.0" parse-json "^5.2.0" +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + 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" + cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" @@ -642,6 +954,33 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" +dotenv@^16.4.5: + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +elliptic@^6.5.7: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + 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" + emoji-regex@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" @@ -671,11 +1010,23 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + escalade@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" @@ -686,6 +1037,27 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + ethereum-cryptography@^2.0.0: version "2.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz#1352270ed3b339fe25af5ceeadcf1b9c8e30768a" @@ -696,11 +1068,43 @@ ethereum-cryptography@^2.0.0: "@scure/bip32" "1.3.3" "@scure/bip39" "1.2.2" -eventemitter3@^5.0.1: +ethereumjs-util@^7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethers@^6.13.0, ethers@^6.13.1: + version "6.16.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.16.0.tgz#fff9b4f05d7a359c774ad6e91085a800f7fccf65" + integrity sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A== + dependencies: + "@adraffy/ens-normalize" "1.10.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.17.1" + +eventemitter3@5.0.1, eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + execa@8.0.1, execa@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" @@ -794,7 +1198,14 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -"forge-std@github:foundry-rs/forge-std#1.9.2": +for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +"forge-std@github:foundry-rs/forge-std#v1.9.2": version "1.9.2" resolved "https://codeload.github.com/foundry-rs/forge-std/tar.gz/1714bee72e286e73f76e320d110e0eaf5c4e649d" @@ -847,6 +1258,30 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stdin@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" @@ -934,6 +1369,11 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -970,6 +1410,11 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" @@ -977,13 +1422,40 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" -hasown@^2.0.0: +hash-base@^3.0.0, hash-base@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.2.tgz#79d72def7611c3f6e3c3b5730652638001b10a74" + integrity sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg== + dependencies: + inherits "^2.0.4" + readable-stream "^2.3.8" + safe-buffer "^5.2.1" + to-buffer "^1.2.1" + +hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -1027,7 +1499,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1055,7 +1527,7 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-callable@^1.1.3: +is-callable@^1.1.3, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== @@ -1123,6 +1595,13 @@ is-text-path@^2.0.0: dependencies: text-extensions "^2.0.0" +is-typed-array@^1.1.14: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + is-typed-array@^1.1.3: version "1.1.13" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" @@ -1135,11 +1614,26 @@ is-windows@^1.0.1: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isows@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.7.tgz#1c06400b7eed216fbba3bcbd68f12490fc342915" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + jiti@^1.19.1: version "1.21.0" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" @@ -1196,6 +1690,15 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +keccak@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + lilconfig@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc" @@ -1307,6 +1810,20 @@ log-update@^6.0.0: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -1357,6 +1874,16 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@^5.0.1: version "5.1.6" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" @@ -1374,6 +1901,28 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.2.0: + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + npm-run-path@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" @@ -1407,6 +1956,20 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +ox@0.14.7: + version "0.14.7" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.14.7.tgz#efe6770f7a138f823fb2df26001b679c2565b0a4" + integrity sha512-zSQ/cfBdolj7U4++NAvH7sI+VG0T3pEohITCgcQj8KlawvTDY4vGVhDT64Atsm0d6adWfIYHDpu88iUBMMp+AQ== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.2.3" + eventemitter3 "5.0.1" + p-limit@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" @@ -1463,6 +2026,18 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pbkdf2@^3.0.17: + version "3.1.5" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.5.tgz#444a59d7a259a95536c56e80c89de31cc01ed366" + integrity sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ== + dependencies: + create-hash "^1.2.0" + create-hmac "^1.1.7" + ripemd160 "^2.0.3" + safe-buffer "^5.2.1" + sha.js "^2.4.12" + to-buffer "^1.2.1" + picocolors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" @@ -1493,6 +2068,11 @@ prettier@^2.8.3: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -1503,11 +2083,52 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pvtsutils@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.3.6.tgz#ec46e34db7422b9e4fdc5490578c1883657d6001" + integrity sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg== + dependencies: + tslib "^2.8.1" + +pvutils@^1.1.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.5.tgz#84b0dea4a5d670249aa9800511804ee0b7c2809c" + integrity sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readable-stream@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -1554,6 +2175,21 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== +ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.3.tgz#9be54e4ba5e3559c8eee06a25cd7648bbccdf5a8" + integrity sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA== + dependencies: + hash-base "^3.1.2" + inherits "^2.0.4" + +rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -1561,6 +2197,30 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +scrypt-js@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secp256k1@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.4.tgz#58f0bfe1830fe777d9ca1ffc7574962a8189f8ab" + integrity sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw== + dependencies: + elliptic "^6.5.7" + node-addon-api "^5.0.0" + node-gyp-build "^4.2.0" + semver@^5.5.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -1576,7 +2236,12 @@ semver@^7.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== -set-function-length@^1.2.1: +semver@^7.6.2, semver@^7.7.2: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + +set-function-length@^1.2.1, set-function-length@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== @@ -1588,6 +2253,20 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +sha.js@^2.4.0, sha.js@^2.4.12, sha.js@^2.4.8: + version "2.4.12" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.12.tgz#eb8b568bf383dfd1867a32c3f2b74eb52bdbf23f" + integrity sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + to-buffer "^1.2.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -1746,6 +2425,20 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -1812,6 +2505,15 @@ tmp@0.0.33: dependencies: os-tmpdir "~1.0.2" +to-buffer@^1.2.0, to-buffer@^1.2.1, to-buffer@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.2.tgz#ffe59ef7522ada0a2d1cb5dfe03bb8abc3cdc133" + integrity sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw== + dependencies: + isarray "^2.0.5" + safe-buffer "^5.2.1" + typed-array-buffer "^1.0.3" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -1819,11 +2521,40 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unicorn-magic@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" @@ -1841,6 +2572,11 @@ uri-js@^4.2.2, uri-js@^4.4.1: dependencies: punycode "^2.1.0" +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" @@ -1852,6 +2588,20 @@ util@^0.12.5: is-typed-array "^1.1.3" which-typed-array "^1.1.2" +viem@^2.21.8: + version "2.47.6" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.47.6.tgz#0249c166d5e0555074ffd3d320f2be2057551796" + integrity sha512-zExmbI99NGvMdYa7fmqSTLgkwh48dmhgEqFrUgkpL4kfG4XkVefZ8dZqIKVUhZo6Uhf0FrrEXOsHm9LUyIvI2Q== + dependencies: + "@noble/curves" "1.9.1" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + abitype "1.2.3" + isows "1.0.7" + ox "0.14.7" + ws "8.18.3" + web3-errors@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/web3-errors/-/web3-errors-1.1.4.tgz#5667a0a5f66fc936e101ef32032ccc1e8ca4d5a1" @@ -1897,6 +2647,19 @@ web3-validator@^2.0.5: web3-types "^1.5.0" zod "^3.21.4" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-typed-array@^1.1.14, which-typed-array@^1.1.2: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" @@ -1908,6 +2671,19 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.2: gopd "^1.0.1" has-tostringtag "^1.0.2" +which-typed-array@^1.1.16: + version "1.1.20" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.20.tgz#3fdb7adfafe0ea69157b1509f3a1cd892bd1d122" + integrity sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + which@^1.2.14: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -1945,6 +2721,16 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +ws@8.18.3: + version "8.18.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" From 98ef02bf50c550e883e7280f0ae0779f338f98fb Mon Sep 17 00:00:00 2001 From: ali Date: Mon, 23 Mar 2026 20:51:07 +0330 Subject: [PATCH 10/14] feat: expand upgrade documentation for Arbitrum and Polygon change the test file naming to be compatible with the repo convention --- PRODUCTION_UPGRADE.md | 42 +++++++++++++ README.md | 2 +- script/TestUpgrade.s.sol | 98 ------------------------------- test/UpgradeDonationHandler.t.sol | 90 ++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 99 deletions(-) delete mode 100644 script/TestUpgrade.s.sol create mode 100644 test/UpgradeDonationHandler.t.sol diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md index 5b178f9..329927a 100644 --- a/PRODUCTION_UPGRADE.md +++ b/PRODUCTION_UPGRADE.md @@ -6,7 +6,9 @@ This guide covers upgrading DonationHandler on all production networks. Based on your deployments: - βœ… Ethereum Mainnet (Chain ID: 1) +- βœ… Arbitrum (Chain ID: 42161) - βœ… Optimism (Chain ID: 10) +- βœ… Polygon (Chain ID: 137) - βœ… Gnosis (Chain ID: 100) - βœ… Base (Chain ID: 8453) - βœ… Celo (Chain ID: 42220) @@ -70,7 +72,9 @@ ETHEREUM_PROXY=0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 ETHEREUM_PROXY_ADMIN=0xECE9bE2e4b0c9a2C9E305feA6Ead25d310477409 # Check other networks in your broadcast folder: +cat broadcast/DeployDonationHandler.s.sol/42161/run-latest.json | grep "contractAddress" # Arbitrum cat broadcast/DeployDonationHandler.s.sol/10/run-latest.json | grep "contractAddress" # Optimism +cat broadcast/DeployDonationHandler.s.sol/137/run-latest.json | grep "contractAddress" # Polygon cat broadcast/DeployDonationHandler.s.sol/100/run-latest.json | grep "contractAddress" # Gnosis cat broadcast/DeployDonationHandler.s.sol/8453/run-latest.json | grep "contractAddress" # Base cat broadcast/DeployDonationHandler.s.sol/42220/run-latest.json | grep "contractAddress" # Celo @@ -132,6 +136,25 @@ cast send $PROXY_ADDRESS \ Once Ethereum mainnet is successful, upgrade other networks. +### Arbitrum (Chain ID: 42161) + +```bash +# Setup +export PROXY_ADDRESS=YOUR_ARBITRUM_PROXY +export PROXY_ADMIN_ADDRESS=YOUR_ARBITRUM_PROXY_ADMIN +export ARBITRUM_RPC=your_arbitrum_rpc + +# Upgrade +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $ARBITRUM_RPC \ + --broadcast \ + --verify \ + -vvvv + +# Verify on Arbiscan +# https://arbiscan.io/address/YOUR_PROXY +``` + ### Optimism (Chain ID: 10) ```bash @@ -208,6 +231,25 @@ forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ # https://celoscan.io/address/YOUR_PROXY ``` +### Polygon (Chain ID: 137) + +```bash +# Setup +export PROXY_ADDRESS=YOUR_POLYGON_PROXY +export PROXY_ADMIN_ADDRESS=YOUR_POLYGON_PROXY_ADMIN +export POLYGON_RPC=your_polygon_rpc + +# Upgrade +forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ + --rpc-url $POLYGON_RPC \ + --broadcast \ + --verify \ + -vvvv + +# Verify on Polygonscan +# https://polygonscan.com/address/YOUR_PROXY +``` + ## βœ… Step 4: Post-Upgrade Verification (All Networks) For each network, verify: diff --git a/README.md b/README.md index 4453c0e..2f19e66 100644 --- a/README.md +++ b/README.md @@ -318,7 +318,7 @@ The upgrade script: 3. Preserves all existing state and data 4. Maintains the same proxy address for users -See `script/UpgradeDonationHandler.s.sol` and `script/TestUpgrade.s.sol` for implementation details. +See `script/UpgradeDonationHandler.s.sol` and `test/UpgradeDonationHandler.t.sol` for implementation details. ## Export And Publish diff --git a/script/TestUpgrade.s.sol b/script/TestUpgrade.s.sol deleted file mode 100644 index a5a8920..0000000 --- a/script/TestUpgrade.s.sol +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.22; - -import {DonationHandler} from '../src/contracts/DonationHandler.sol'; -import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; -import {ITransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; -import {Script} from 'forge-std/Script.sol'; -import {console} from 'forge-std/console.sol'; - -/// @title TestUpgrade -/// @notice Script to test the upgrade locally or on a fork before deploying to mainnet -contract TestUpgrade is Script { - function run() external { - address proxyAddress = vm.envAddress('PROXY_ADDRESS'); - address proxyAdminAddress = vm.envAddress('PROXY_ADMIN_ADDRESS'); - uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); - - console.log('=== Testing DonationHandler Upgrade ==='); - console.log('Proxy:', proxyAddress); - console.log('ProxyAdmin:', proxyAdminAddress); - - // Get current implementation before upgrade - DonationHandler proxy = DonationHandler(payable(proxyAddress)); - bytes32 implSlot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1); - address oldImplementation = address(uint160(uint256(vm.load(proxyAddress, implSlot)))); - console.log('Old Implementation:', oldImplementation); - - vm.startBroadcast(deployerPrivateKey); - - // Deploy new implementation - DonationHandler newImplementation = new DonationHandler(); - console.log('New Implementation:', address(newImplementation)); - - // Upgrade - ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress); - proxyAdmin.upgradeAndCall(ITransparentUpgradeableProxy(proxyAddress), address(newImplementation), ''); - - vm.stopBroadcast(); - - // Verify upgrade - address currentImplementation = address(uint160(uint256(vm.load(proxyAddress, implSlot)))); - console.log('Current Implementation:', currentImplementation); - - require(currentImplementation == address(newImplementation), 'Upgrade failed - implementation not updated'); - console.log('SUCCESS: Upgrade completed!'); - - // Test the new validation - console.log('\n=== Testing Bug Fix ==='); - _testBugFix(proxy); - } - - function _testBugFix(DonationHandler proxy) internal { - address recipient = address(0x1234567890123456789012345678901234567890); - - // Test 1: Should revert when amounts sum < totalAmount - console.log('Test 1: amounts sum < totalAmount should revert'); - address[] memory recipients1 = new address[](1); - recipients1[0] = recipient; - uint256[] memory amounts1 = new uint256[](1); - amounts1[0] = 8 ether; // Only 8 ETH allocated - bytes[] memory data1 = new bytes[](1); - - vm.expectRevert('Amounts do not match total'); - proxy.donateManyETH{value: 10 ether}(10 ether, recipients1, amounts1, data1); - console.log(' PASS: Correctly reverted'); - - // Test 2: Should revert when amounts sum > totalAmount - console.log('Test 2: amounts sum > totalAmount should revert'); - address[] memory recipients2 = new address[](1); - recipients2[0] = recipient; - uint256[] memory amounts2 = new uint256[](1); - amounts2[0] = 12 ether; // 12 ETH allocated - bytes[] memory data2 = new bytes[](1); - - vm.expectRevert('Amounts do not match total'); - proxy.donateManyETH{value: 10 ether}(10 ether, recipients2, amounts2, data2); - console.log(' PASS: Correctly reverted'); - - // Test 3: Should succeed when amounts sum == totalAmount - console.log('Test 3: amounts sum == totalAmount should succeed'); - address[] memory recipients3 = new address[](2); - recipients3[0] = recipient; - recipients3[1] = address(0x9876543210987654321098765432109876543210); - uint256[] memory amounts3 = new uint256[](2); - amounts3[0] = 6 ether; - amounts3[1] = 4 ether; // Total = 10 ETH - bytes[] memory data3 = new bytes[](2); - - uint256 contractBalanceBefore = address(proxy).balance; - proxy.donateManyETH{value: 10 ether}(10 ether, recipients3, amounts3, data3); - uint256 contractBalanceAfter = address(proxy).balance; - - require(contractBalanceAfter == contractBalanceBefore, 'ETH stuck in contract!'); - console.log(' PASS: Donation succeeded and no ETH stuck'); - - console.log('\n=== All Tests Passed! ==='); - } -} diff --git a/test/UpgradeDonationHandler.t.sol b/test/UpgradeDonationHandler.t.sol new file mode 100644 index 0000000..a1a1db7 --- /dev/null +++ b/test/UpgradeDonationHandler.t.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.22; + +import {DonationHandler} from '../src/contracts/DonationHandler.sol'; +import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; +import { + ITransparentUpgradeableProxy, + TransparentUpgradeableProxy +} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; +import 'forge-std/Test.sol'; + +contract DonationHandlerUpgradeTest is Test { + DonationHandler public donationHandler; + TransparentUpgradeableProxy public proxy; + ProxyAdmin public proxyAdmin; + + bytes32 internal constant IMPLEMENTATION_SLOT = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1); + bytes32 internal constant ADMIN_SLOT = bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1); + + function setUp() public { + DonationHandler implementation = new DonationHandler(); + proxy = new TransparentUpgradeableProxy( + address(implementation), address(this), abi.encodeCall(DonationHandler.initialize, ()) + ); + donationHandler = DonationHandler(payable(address(proxy))); + proxyAdmin = ProxyAdmin(_slotAddress(address(proxy), ADMIN_SLOT)); + + vm.deal(address(this), 20 ether); + } + + function testUpgradeKeepsOwnerAndUpdatesImplementation() public { + address oldImplementation = _slotAddress(address(proxy), IMPLEMENTATION_SLOT); + assertEq(donationHandler.owner(), address(this)); + + DonationHandler newImplementation = new DonationHandler(); + + proxyAdmin.upgradeAndCall(ITransparentUpgradeableProxy(payable(address(proxy))), address(newImplementation), ''); + + address currentImplementation = _slotAddress(address(proxy), IMPLEMENTATION_SLOT); + + assertEq(currentImplementation, address(newImplementation)); + assertTrue(currentImplementation != oldImplementation); + assertEq(donationHandler.owner(), address(this)); + } + + function testUpgradedProxyPreservesDonationChecks() public { + DonationHandler newImplementation = new DonationHandler(); + proxyAdmin.upgradeAndCall(ITransparentUpgradeableProxy(payable(address(proxy))), address(newImplementation), ''); + + address[] memory recipients = new address[](2); + recipients[0] = makeAddr('recipient1'); + recipients[1] = makeAddr('recipient2'); + + uint256[] memory amounts = new uint256[](2); + amounts[0] = 6 ether; + amounts[1] = 4 ether; + + bytes[] memory data = new bytes[](2); + + uint256 recipient1Before = recipients[0].balance; + uint256 recipient2Before = recipients[1].balance; + + donationHandler.donateManyETH{value: 10 ether}(10 ether, recipients, amounts, data); + + assertEq(recipients[0].balance, recipient1Before + 6 ether); + assertEq(recipients[1].balance, recipient2Before + 4 ether); + assertEq(address(donationHandler).balance, 0); + assertEq(donationHandler.owner(), address(this)); + } + + function testUpgradedProxyRejectsMismatchedAmounts() public { + DonationHandler newImplementation = new DonationHandler(); + proxyAdmin.upgradeAndCall(ITransparentUpgradeableProxy(payable(address(proxy))), address(newImplementation), ''); + + address[] memory recipients = new address[](1); + recipients[0] = makeAddr('recipient'); + + uint256[] memory amounts = new uint256[](1); + amounts[0] = 8 ether; + + bytes[] memory data = new bytes[](1); + + vm.expectRevert('Amounts do not match total'); + donationHandler.donateManyETH{value: 10 ether}(10 ether, recipients, amounts, data); + } + + function _slotAddress(address target, bytes32 slot) internal view returns (address) { + return address(uint160(uint256(vm.load(target, slot)))); + } +} From fe45f25f13c402a581d2b8fdc97e07c6c5688826 Mon Sep 17 00:00:00 2001 From: ali Date: Mon, 23 Mar 2026 21:28:55 +0330 Subject: [PATCH 11/14] feat: apply the review comments --- .env.example | 4 +-- PRODUCTION_UPGRADE.md | 15 ++++++---- README.md | 15 +++++----- TESTNET_DEPLOYMENT.md | 11 ++++---- docs/MULTISIG_UPGRADE_GUIDE.md | 25 +++++++++++------ package.json | 4 +-- script/DeployDonationHandler.s.sol | 6 ---- .../DeployDonationHandlerImplementation.s.sol | 6 ++-- script/UpgradeDonationHandler.s.sol | 2 ++ scripts/submit-upgrade-to-safe.mjs | 28 ++++++++++--------- scripts/upgrade-direct.sh | 2 ++ test/UpgradeDonationHandler.t.sol | 2 +- 12 files changed, 66 insertions(+), 54 deletions(-) diff --git a/.env.example b/.env.example index 5865918..cf9f4e1 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,6 @@ MAINNET_RPC= -MAINNET_DEPLOYER_NAME= SEPOLIA_RPC= -SEPOLIA_DEPLOYER_NAME= BASE_RPC= ARBITRUM_RPC= @@ -11,6 +9,8 @@ CELO_RPC= OPTIMISM_RPC= POLYGON_RPC= +PRIVATE_KEY= # required: private key for deployer / Forge scripts + # For upgrade:submit-to-safe (proposer must be a Safe owner) SAFE_ADDRESS= PROXY_ADMIN_ADDRESS= diff --git a/PRODUCTION_UPGRADE.md b/PRODUCTION_UPGRADE.md index 329927a..a1a4f65 100644 --- a/PRODUCTION_UPGRADE.md +++ b/PRODUCTION_UPGRADE.md @@ -95,7 +95,7 @@ yarn upgrade:mainnet:simulate ``` **Expected Output:** -``` +```text === Upgrading DonationHandler === Proxy Address: 0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 ... @@ -116,7 +116,9 @@ yarn upgrade:mainnet ```bash # Check implementation changed -cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $MAINNET_RPC +cast storage $PROXY_ADDRESS \ + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc \ + --rpc-url $MAINNET_RPC | sed 's/^0x000000000000000000000000/0x/' # Check on Etherscan # Go to: https://etherscan.io/address/0x97b2cb568e0880B99Cd16EFc6edFF5272Aa02676 @@ -185,6 +187,7 @@ export GNOSIS_RPC=https://rpc.gnosischain.com # Upgrade forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ --rpc-url $GNOSIS_RPC \ + --legacy \ --broadcast \ --verify \ -vvvv @@ -223,6 +226,7 @@ export CELO_RPC=https://forno.celo.org # Upgrade forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ --rpc-url $CELO_RPC \ + --legacy \ --broadcast \ --verify \ -vvvv @@ -257,7 +261,9 @@ For each network, verify: ### 1. Implementation Changed ```bash # Get new implementation -cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $RPC_URL +cast storage $PROXY_ADDRESS \ + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc \ + --rpc-url $RPC_URL | sed 's/^0x000000000000000000000000/0x/' # Should be different from before ``` @@ -277,14 +283,13 @@ cast send $PROXY_ADDRESS \ ### 3. New Validation Works (Bug Fix Specific) ```bash # This should REVERT with "Amounts do not match total" -cast send $PROXY_ADDRESS \ +cast call $PROXY_ADDRESS \ "donateManyETH(uint256,address[],uint256[],bytes[])" \ 1000000000000000000 \ "[0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb]" \ "[800000000000000000]" \ "[]" \ --value 1ether \ - --private-key $PRIVATE_KEY \ --rpc-url $RPC_URL ``` diff --git a/README.md b/README.md index 2f19e66..61843ba 100644 --- a/README.md +++ b/README.md @@ -215,14 +215,10 @@ Configure the `.env` variables and source them: source .env ``` -Import your private keys into Foundry's encrypted keystore: +Set the deployer private key in your environment: ```bash -cast wallet import $MAINNET_DEPLOYER_NAME --interactive -``` - -```bash -cast wallet import $SEPOLIA_DEPLOYER_NAME --interactive +export PRIVATE_KEY=0x... ``` ### Sepolia @@ -298,8 +294,11 @@ forge script script/UpgradeDonationHandler.s.sol:UpgradeDonationHandler \ After upgrading, verify the new implementation: ```bash -# Check current implementation address -cast call $PROXY_ADDRESS "implementation()(address)" --rpc-url $MAINNET_RPC +# TransparentUpgradeableProxy blocks non-admin callers from implementation(), so +# read the EIP-1967 implementation slot directly instead. +cast storage $PROXY_ADDRESS \ + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc \ + --rpc-url $MAINNET_RPC | sed 's/^0x000000000000000000000000/0x/' ``` ### ⚠️ Important Notes diff --git a/TESTNET_DEPLOYMENT.md b/TESTNET_DEPLOYMENT.md index 9a8740c..ac09874 100644 --- a/TESTNET_DEPLOYMENT.md +++ b/TESTNET_DEPLOYMENT.md @@ -132,8 +132,9 @@ Check the transaction on Etherscan to verify it succeeded. Before upgrading, save the current implementation address: ```bash -# Get current implementation address -OLD_IMPL=$(cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $SEPOLIA_RPC) +# TransparentUpgradeableProxy blocks non-admin callers from implementation(), +# so read the EIP-1967 implementation slot directly. +OLD_IMPL=$(cast storage $PROXY_ADDRESS 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc --rpc-url $SEPOLIA_RPC | sed 's/^0x000000000000000000000000/0x/') echo "Old Implementation: $OLD_IMPL" ``` @@ -156,7 +157,7 @@ yarn upgrade:sepolia === Upgrading DonationHandler === Proxy Address: 0x... ProxyAdmin Address: 0x... -New Implementation deployed to: 0x... +New Implementation: 0x... Proxy upgraded successfully! ``` @@ -165,8 +166,8 @@ Proxy upgraded successfully! **Check 1: Implementation Address Changed** ```bash -# Get new implementation address -NEW_IMPL=$(cast call $PROXY_ADDRESS "0x5c60da1b" --rpc-url $SEPOLIA_RPC) +# Get new implementation address from the EIP-1967 implementation slot +NEW_IMPL=$(cast storage $PROXY_ADDRESS 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc --rpc-url $SEPOLIA_RPC | sed 's/^0x000000000000000000000000/0x/') echo "New Implementation: $NEW_IMPL" # Compare with old implementation from Step 8 diff --git a/docs/MULTISIG_UPGRADE_GUIDE.md b/docs/MULTISIG_UPGRADE_GUIDE.md index a5ee8ff..1f201e4 100644 --- a/docs/MULTISIG_UPGRADE_GUIDE.md +++ b/docs/MULTISIG_UPGRADE_GUIDE.md @@ -187,11 +187,12 @@ The script will create the upgrade transaction, sign it with the proposer key, a 4. **Contract interaction:** - Choose **Write contract** (or β€œContract interaction”). - - Find the function **`upgrade`** (or add it as a custom call; see below). + - Find the function **`upgradeAndCall`** (or add it as a custom call; see below). -5. **Function: `upgrade`** +5. **Function: `upgradeAndCall`** - **Parameter 1 – `proxy` (address):** the **DonationHandler proxy** address. - **Parameter 2 – `implementation` (address):** the **new implementation** address. + - **Parameter 3 – `data` (bytes):** `0x` 6. **Value:** leave as **0**. @@ -204,19 +205,25 @@ The script will create the upgrade transaction, sign it with the proposer key, a Use **Contract interaction** with **Custom data**: - **To:** ProxyAdmin address -- **Data (hex):** use the ABI-encoded call: +- **Data (hex):** generate the exact calldata from the repo, then paste it into Safe: ```text upgradeAndCall(address,address,bytes) ``` - Encoded with: - - Encode the call with `proxy`, `implementation`, and empty `data = 0x`. - You can get the exact calldata from a block explorer (e.g. Etherscan) by going to the ProxyAdmin contract β†’ **Write** β†’ **upgradeAndCall** and encoding the values, or by using a small script/tool that encodes the call. + Preferred: + ```bash + yarn upgrade:generate-payload [safe_address] [chain] + ``` + + That script prints the full hex calldata to paste into the Safe UI. + + Or run `cast` directly: + ```bash + cast calldata "upgradeAndCall(address,address,bytes)" 0x + ``` - Or use an online ABI encoder: - - Function: `upgradeAndCall(address proxy, address implementation, bytes data)` - - Arguments: `[ , , 0x ]` + This outputs the exact calldata for `upgradeAndCall(proxy, implementation, 0x)`. --- diff --git a/package.json b/package.json index 0cc7107..3d244b7 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "coverage": "forge coverage --ir-minimum --report summary --report lcov --match-path 'test/unit/*'", "deploy:implementation": "./scripts/deploy-implementation.sh", - "deploy:mainnet": "bash -c 'source .env && forge script Deploy --rpc-url $MAINNET_RPC --account $MAINNET_DEPLOYER_NAME --broadcast --verify --chain mainnet -vvvvv'", - "deploy:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify -vvvv'", + "deploy:mainnet": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $MAINNET_RPC --broadcast --verify --chain mainnet -vvvvv'", + "deploy:sepolia": "bash -c 'source .env && forge script script/DeployDonationHandler.s.sol:DeployDonationHandler --rpc-url $SEPOLIA_RPC --broadcast --verify --chain sepolia -vvvv'", "lint:check": "yarn lint:sol && forge fmt --check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix", "lint:natspec": "npx @defi-wonderland/natspec-smells --config natspec-smells.config.js", diff --git a/script/DeployDonationHandler.s.sol b/script/DeployDonationHandler.s.sol index 80afeef..b86a3a7 100644 --- a/script/DeployDonationHandler.s.sol +++ b/script/DeployDonationHandler.s.sol @@ -5,17 +5,11 @@ pragma solidity ^0.8.22; /// For upgrading an existing proxy, use UpgradeDonationHandler.s.sol instead. import {DonationHandler} from '../src/contracts/DonationHandler.sol'; -import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol'; import {TransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; import {Script} from 'forge-std/Script.sol'; import {console} from 'forge-std/console.sol'; contract DeployDonationHandler is Script { - address public constant ETHEREUM_PROXY_ADMIN = 0x7cD4eAAed06fA2270e0C063B7aBDa576a0ad149F; - address public constant GNOSIS_PROXY_ADMIN = 0x076C250700D210e6cf8A27D1EB1Fd754FB487986; - address public constant OPTIMISM_PROXY_ADMIN = 0x2f2c819210191750F2E11F7CfC5664a0eB4fd5e6; - address public constant POLYGON_PROXY_ADMIN = 0x7a5D2A00a25b95fd8739bc52Cd79f8F971C37Ca1; - function run() external { uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); address deployer = vm.addr(deployerPrivateKey); diff --git a/script/DeployDonationHandlerImplementation.s.sol b/script/DeployDonationHandlerImplementation.s.sol index 0db2238..40a2c9d 100644 --- a/script/DeployDonationHandlerImplementation.s.sol +++ b/script/DeployDonationHandlerImplementation.s.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.22; /// @notice Deploys and verifies only the DonationHandler implementation (no proxy, no upgrade). /// Use this when you are not the ProxyAdmin owner: deploy + verify, then give the implementation -/// address to the owner so they can call proxyAdmin.upgrade(proxy, implementationAddress). +/// address to the owner so they can call proxyAdmin.upgradeAndCall(proxy, implementationAddress, ''). import {DonationHandler} from '../src/contracts/DonationHandler.sol'; import {Script} from 'forge-std/Script.sol'; @@ -24,7 +24,7 @@ contract DeployDonationHandlerImplementation is Script { console.log('\n=== Hand off to proxy owner ==='); console.log('Give this address to the ProxyAdmin owner to run:'); - console.log(' proxyAdmin.upgrade(proxy,', address(implementation), ')'); - console.log('export NEW_IMPLEMENTATION_ADDRESS=', address(implementation)); + console.log(string.concat(' proxyAdmin.upgradeAndCall(proxy, ', vm.toString(address(implementation)), ", '')")); + console.log(string.concat('export NEW_IMPLEMENTATION_ADDRESS=', vm.toString(address(implementation)))); } } diff --git a/script/UpgradeDonationHandler.s.sol b/script/UpgradeDonationHandler.s.sol index c3baf64..7bcffd2 100644 --- a/script/UpgradeDonationHandler.s.sol +++ b/script/UpgradeDonationHandler.s.sol @@ -11,11 +11,13 @@ contract UpgradeDonationHandler is Script { /// Set PROXY_ADDRESS, PROXY_ADMIN_ADDRESS, NEW_IMPLEMENTATION_ADDRESS in .env (deploy impl via deploy:implementation first). function run() external { uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY'); + address deployer = vm.addr(deployerPrivateKey); address proxyAddress = vm.envAddress('PROXY_ADDRESS'); address proxyAdminAddress = vm.envAddress('PROXY_ADMIN_ADDRESS'); address newImplementation = vm.envAddress('NEW_IMPLEMENTATION_ADDRESS'); console.log('=== Upgrading DonationHandler ==='); + console.log('Deployer:', deployer); console.log('Proxy Address:', proxyAddress); console.log('ProxyAdmin Address:', proxyAdminAddress); console.log('New Implementation:', newImplementation); diff --git a/scripts/submit-upgrade-to-safe.mjs b/scripts/submit-upgrade-to-safe.mjs index 67bf054..28fb546 100644 --- a/scripts/submit-upgrade-to-safe.mjs +++ b/scripts/submit-upgrade-to-safe.mjs @@ -139,6 +139,17 @@ function main() { (async() => { try { + const safeApiKey = (process.env.SAFE_API_KEY || '').trim(); + if (!safeApiKey) { + throw new Error( + 'SAFE_API_KEY is required. Get a free key at https://developer.safe.global and add SAFE_API_KEY=your_key to .env' + ); + } + const apiKit = new SafeApiKit({ + chainId, + apiKey: safeApiKey, + }); + const protocolKit = await Safe.init({ provider: rpcUrl, signer: proposerPk, @@ -149,6 +160,8 @@ function main() { if (nonce !== undefined) { txOptions.nonce = nonce; + } else { + txOptions.nonce = await apiKit.getNextNonce(safeAddress); } const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData], @@ -157,17 +170,6 @@ function main() { const safeTxHash = await protocolKit.getTransactionHash(safeTransaction); const signature = await protocolKit.signHash(safeTxHash); - const safeApiKey = (process.env.SAFE_API_KEY || '').trim(); - if (!safeApiKey) { - throw new Error( - 'SAFE_API_KEY is required. Get a free key at https://developer.safe.global and add SAFE_API_KEY=your_key to .env' - ); - } - const apiKit = new SafeApiKit({ - chainId, - apiKey: safeApiKey, - }); - await apiKit.proposeTransaction({ safeAddress, safeTransactionData: safeTransaction.data, @@ -178,7 +180,7 @@ function main() { const slug = SAFE_APP_CHAIN_SLUG[chain ? chain.toLowerCase() : 'mainnet'] || 'eth'; console.log('Proposal submitted to Safe Transaction Service.'); - if (nonce !== undefined) console.log('Nonce used:', nonce); + console.log('Nonce used:', txOptions.nonce); console.log('Safe tx hash:', safeTxHash); console.log('View in Safe:', `https://app.safe.global/transactions/queue?safe=${slug}:${safeAddress}`); } catch (err) { @@ -197,7 +199,7 @@ function main() { console.error('API response:', body); } if (err && err.message && (err.message.includes('Unprocessable') || err.message.includes('422'))) { - console.error('\nCommon causes: Safe at SAFE_ADDRESS may not exist on this chain, or proposer is not an owner of that Safe on this chain. Use the correct Safe address for Polygon.'); + console.error(`\nCommon causes: Safe at SAFE_ADDRESS may not exist on ${chain}, or proposer is not an owner of that Safe on this chain. Double-check the Safe address and chain-specific config.`); } process.exit(1); } diff --git a/scripts/upgrade-direct.sh b/scripts/upgrade-direct.sh index a2c626c..a47a1d4 100755 --- a/scripts/upgrade-direct.sh +++ b/scripts/upgrade-direct.sh @@ -19,7 +19,9 @@ if [[ "${2:-}" == "--simulate" ]]; then fi cd "$(dirname "$0")/.." +set -a source .env +set +a # Derive RPC env var from chain name: base -> BASE_RPC, mainnet -> MAINNET_RPC RPC_SUFFIX=$(echo "$CHAIN" | tr '[:lower:]' '[:upper:]' | tr '-' '_') diff --git a/test/UpgradeDonationHandler.t.sol b/test/UpgradeDonationHandler.t.sol index a1a1db7..e489f5e 100644 --- a/test/UpgradeDonationHandler.t.sol +++ b/test/UpgradeDonationHandler.t.sol @@ -7,7 +7,7 @@ import { ITransparentUpgradeableProxy, TransparentUpgradeableProxy } from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol'; -import 'forge-std/Test.sol'; +import {Test} from 'forge-std/Test.sol'; contract DonationHandlerUpgradeTest is Test { DonationHandler public donationHandler; From 9d309eb7d1fe4b57eeb903639da38f0b95997132 Mon Sep 17 00:00:00 2001 From: ali Date: Mon, 23 Mar 2026 21:36:25 +0330 Subject: [PATCH 12/14] feat: apply review comments on my PR by coderabbit --- .env.example | 6 ++++-- TESTNET_DEPLOYMENT.md | 2 +- script/DeployDonationHandler.s.sol | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.env.example b/.env.example index cf9f4e1..f6dde2f 100644 --- a/.env.example +++ b/.env.example @@ -9,7 +9,8 @@ CELO_RPC= OPTIMISM_RPC= POLYGON_RPC= -PRIVATE_KEY= # required: private key for deployer / Forge scripts +# required: private key for deployer / Forge scripts +PRIVATE_KEY= # For upgrade:submit-to-safe (proposer must be a Safe owner) SAFE_ADDRESS= @@ -17,6 +18,7 @@ PROXY_ADMIN_ADDRESS= PROXY_ADDRESS= NEW_IMPLEMENTATION_ADDRESS= PROPOSER_PRIVATE_KEY= -SAFE_API_KEY= # required: get at https://developer.safe.global +# required: get at https://developer.safe.global +SAFE_API_KEY= ETHERSCAN_API_KEY= diff --git a/TESTNET_DEPLOYMENT.md b/TESTNET_DEPLOYMENT.md index ac09874..1546183 100644 --- a/TESTNET_DEPLOYMENT.md +++ b/TESTNET_DEPLOYMENT.md @@ -17,7 +17,7 @@ This guide walks you through deploying DonationHandler to Sepolia testnet and te 1. **Get Sepolia ETH** (for gas fees) - Visit [Sepolia Faucet](https://sepoliafaucet.com/) - - Or [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) + - Or [Alchemy Sepolia Faucet](https://www.alchemy.com/faucets/ethereum-sepolia) - You'll need ~0.05 ETH for deployment + upgrade 2. **Get an Etherscan API Key** (for verification) diff --git a/script/DeployDonationHandler.s.sol b/script/DeployDonationHandler.s.sol index b86a3a7..9a922da 100644 --- a/script/DeployDonationHandler.s.sol +++ b/script/DeployDonationHandler.s.sol @@ -43,7 +43,7 @@ contract DeployDonationHandler is Script { console.log('Proxy:', address(proxy)); console.log('ProxyAdmin:', proxyAdmin); console.log('\n=== Save these for upgrading ==='); - console.log('export PROXY_ADDRESS=', address(proxy)); - console.log('export PROXY_ADMIN_ADDRESS=', proxyAdmin); + console.log(string.concat('export PROXY_ADDRESS=', vm.toString(address(proxy)))); + console.log(string.concat('export PROXY_ADMIN_ADDRESS=', vm.toString(proxyAdmin))); } } From 55a71a30ec6ba147f0cae797bb3ef10c693257b9 Mon Sep 17 00:00:00 2001 From: ali Date: Mon, 27 Apr 2026 17:19:50 +0330 Subject: [PATCH 13/14] feat: support no-return ERC20 donations Made-with: Cursor --- src/contracts/DonationHandler.sol | 6 ++- test/DonationHandler.t.sol | 50 ++++++++++++++++++++++++- test/DonationHandlerSetup.t.sol | 35 +++++++++++++++++ test/DonationHandlerStandardTests.t.sol | 15 +++++++- 4 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/contracts/DonationHandler.sol b/src/contracts/DonationHandler.sol index d51b680..9726856 100644 --- a/src/contracts/DonationHandler.sol +++ b/src/contracts/DonationHandler.sol @@ -5,8 +5,11 @@ import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol'; import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol'; import '@openzeppelin/contracts/interfaces/IERC20.sol'; +import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; contract DonationHandler is OwnableUpgradeable, ReentrancyGuardUpgradeable { + using SafeERC20 for IERC20; + address private constant ETH_TOKEN_ADDRESS = address(0); /// @notice Event emitted when a donation is made @@ -185,8 +188,7 @@ contract DonationHandler is OwnableUpgradeable, ReentrancyGuardUpgradeable { /// @param recipientAddress The address of the recipient of the donation function _handleERC20(address token, uint256 amount, address recipientAddress, bytes memory data) internal { if (token == ETH_TOKEN_ADDRESS || recipientAddress == ETH_TOKEN_ADDRESS || amount == 0) revert InvalidInput(); - bool success = IERC20(token).transferFrom(msg.sender, recipientAddress, amount); - require(success, 'ERC20 transfer failed'); + IERC20(token).safeTransferFrom(msg.sender, recipientAddress, amount); emit DonationMade(recipientAddress, amount, token, data); } diff --git a/test/DonationHandler.t.sol b/test/DonationHandler.t.sol index 581cd18..2c705c4 100644 --- a/test/DonationHandler.t.sol +++ b/test/DonationHandler.t.sol @@ -24,6 +24,41 @@ contract FailingMockERC20 is ERC20 { } } +contract NoReturnMockERC20 { + string public name = 'NoReturnToken'; + string public symbol = 'NRT'; + uint8 public decimals = 6; + uint256 public totalSupply = 1_000_000 * 10 ** 6; + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + constructor() { + balanceOf[msg.sender] = totalSupply; + emit Transfer(address(0), msg.sender, totalSupply); + } + + function approve(address spender, uint256 value) external { + allowance[msg.sender][spender] = value; + emit Approval(msg.sender, spender, value); + } + + function transferFrom(address from, address to, uint256 value) external { + require(to != address(0), 'Invalid recipient'); + require(balanceOf[from] >= value, 'Insufficient balance'); + require(allowance[from][msg.sender] >= value, 'Insufficient allowance'); + + allowance[from][msg.sender] -= value; + balanceOf[from] -= value; + balanceOf[to] += value; + + emit Transfer(from, to, value); + } +} + contract DonationHandlerTest is Test { DonationHandler public donationHandler; MockERC20 public mockToken; @@ -262,10 +297,23 @@ contract DonationHandlerTest is Test { uint256 amount = 100 * 10 ** 18; failingToken.approve(address(donationHandler), amount); - vm.expectRevert('ERC20 transfer failed'); + vm.expectRevert(); donationHandler.donateERC20(address(failingToken), recipient1, amount, data); } + function test_WhenMakingERC20DonationWithNoReturnToken() external { + NoReturnMockERC20 noReturnToken = new NoReturnMockERC20(); + uint256 donationAmount = 100 * 10 ** noReturnToken.decimals(); + bytes memory data = ''; + + noReturnToken.approve(address(donationHandler), donationAmount); + + _expectDonationEvent(recipient1, donationAmount, address(noReturnToken)); + donationHandler.donateERC20(address(noReturnToken), recipient1, donationAmount, data); + + assertEq(noReturnToken.balanceOf(recipient1), donationAmount); + } + function test_RevertWhen_InitializingTwice() external { vm.expectRevert(Initializable.InvalidInitialization.selector); donationHandler.initialize(); diff --git a/test/DonationHandlerSetup.t.sol b/test/DonationHandlerSetup.t.sol index d06561c..ab96a85 100644 --- a/test/DonationHandlerSetup.t.sol +++ b/test/DonationHandlerSetup.t.sol @@ -24,6 +24,41 @@ contract FailingMockERC20 is ERC20 { } } +contract NoReturnMockERC20 { + string public name = 'NoReturnToken'; + string public symbol = 'NRT'; + uint8 public decimals = 6; + uint256 public totalSupply = 1_000_000 * 10 ** 6; + + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + constructor() { + balanceOf[msg.sender] = totalSupply; + emit Transfer(address(0), msg.sender, totalSupply); + } + + function approve(address spender, uint256 value) external { + allowance[msg.sender][spender] = value; + emit Approval(msg.sender, spender, value); + } + + function transferFrom(address from, address to, uint256 value) external { + require(to != address(0), 'Invalid recipient'); + require(balanceOf[from] >= value, 'Insufficient balance'); + require(allowance[from][msg.sender] >= value, 'Insufficient allowance'); + + allowance[from][msg.sender] -= value; + balanceOf[from] -= value; + balanceOf[to] += value; + + emit Transfer(from, to, value); + } +} + contract DonationHandlerSetup is Test { DonationHandler public donationHandler; MockERC20 public mockToken; diff --git a/test/DonationHandlerStandardTests.t.sol b/test/DonationHandlerStandardTests.t.sol index 3e8a059..88ad713 100644 --- a/test/DonationHandlerStandardTests.t.sol +++ b/test/DonationHandlerStandardTests.t.sol @@ -163,10 +163,23 @@ contract DonationHandlerStandardTests is DonationHandlerSetup { uint256 amount = 100 * 10 ** 18; failingToken.approve(address(donationHandler), amount); - vm.expectRevert('ERC20 transfer failed'); + vm.expectRevert(); donationHandler.donateERC20(address(failingToken), recipient1, amount, data); } + function test_WhenMakingERC20DonationWithNoReturnToken() external { + NoReturnMockERC20 noReturnToken = new NoReturnMockERC20(); + uint256 donationAmount = 100 * 10 ** noReturnToken.decimals(); + bytes memory data = ''; + + noReturnToken.approve(address(donationHandler), donationAmount); + + _expectDonationEvent(recipient1, donationAmount, address(noReturnToken)); + donationHandler.donateERC20(address(noReturnToken), recipient1, donationAmount, data); + + assertEq(noReturnToken.balanceOf(recipient1), donationAmount); + } + function test_RevertWhen_InitializingTwice() external { vm.expectRevert(Initializable.InvalidInitialization.selector); donationHandler.initialize(); From dcf30375a8183d6f542db5a20c0ebed86a8c38da Mon Sep 17 00:00:00 2001 From: ali Date: Mon, 27 Apr 2026 17:31:04 +0330 Subject: [PATCH 14/14] fix: use numeric chainId in upgrade-payload.json for Safe import Map chain names to EIP-155 IDs so Transaction Builder JSON validates; reject unknown chain names. Made-with: Cursor --- scripts/generate-upgrade-payload.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/generate-upgrade-payload.sh b/scripts/generate-upgrade-payload.sh index 2c6705e..6fa81f3 100755 --- a/scripts/generate-upgrade-payload.sh +++ b/scripts/generate-upgrade-payload.sh @@ -21,6 +21,22 @@ NEW_IMPL="${3:-${NEW_IMPLEMENTATION_ADDRESS:?}}" SAFE_ADDRESS="${4:-${SAFE_ADDRESS}}" CHAIN="${5:-${CHAIN:-mainnet}}" +# Numeric chain ID for Safe Transaction Builder JSON (must not be the chain name string) +case "$CHAIN" in + mainnet) CHAIN_ID_NUM=1 ;; + sepolia) CHAIN_ID_NUM=11155111 ;; + base) CHAIN_ID_NUM=8453 ;; + arbitrum) CHAIN_ID_NUM=42161 ;; + optimism) CHAIN_ID_NUM=10 ;; + polygon) CHAIN_ID_NUM=137 ;; + gnosis) CHAIN_ID_NUM=100 ;; + celo) CHAIN_ID_NUM=42220 ;; + *) + echo "Unknown chain name: $CHAIN (expected mainnet, sepolia, base, arbitrum, optimism, polygon, gnosis, celo)" >&2 + exit 1 + ;; +esac + # Normalize chain to Safe app slug (eth, base, arbitrum, etc.) SAFE_CHAIN_SLUG="$CHAIN" case "$CHAIN" in @@ -76,7 +92,7 @@ OUTPUT_JSON="${MULTISIG_PROPOSAL_JSON:-./upgrade-payload.json}" cat > "$OUTPUT_JSON" << EOF { "version": "1.0", - "chainId": "$CHAIN", + "chainId": $CHAIN_ID_NUM, "meta": { "name": "DonationHandler upgrade", "description": "ProxyAdmin.upgradeAndCall(proxy, implementation, 0x)"