Exemplos do Truffle Development Suite

Exemplos do framework de desenvolvimento Ethereum Truffle incluindo contratos inteligentes, testes, implantação, migrações, depuração e fluxos de trabalho de desenvolvimento

💻 Truffle Hello World - Configuração Básica javascript

🟢 simple ⭐⭐

Configuração completa de projeto Truffle com contratos inteligentes, testes, migrações e configuração para desenvolvimento Ethereum

⏱️ 20 min 🏷️ truffle, ethereum, smart contracts, development
Prerequisites: Node.js, Truffle Suite installed, Ganache or other Ethereum client
// Truffle Hello World - Complete Project Setup
// Initialize: truffle init

// ===== truffle-config.js =====
module.exports = {
  // Networks configuration
  networks: {
    development: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*",
    },
    ganache: {
      host: "127.0.0.1",
      port: 7545,
      network_id: "*",
    },
    // Testnet configurations
    goerli: {
      provider: () => {
        const wallet = require('ethereumjs-wallet').default;
        const HDWalletProvider = require('@truffle/hdwallet-provider');
        const mnemonic = process.env.MNEMONIC;
        const infuraKey = process.env.INFURA_KEY;
        return new HDWalletProvider({
          mnemonic: {
            phrase: mnemonic
          },
          providerOrUrl: `https://goerli.infura.io/v3/${infuraKey}`
        });
      },
      network_id: 5,
      gas: 4465030,
      gasPrice: 10000000000,
    },
    sepolia: {
      provider: () => {
        const HDWalletProvider = require('@truffle/hdwallet-provider');
        const privateKey = process.env.PRIVATE_KEY;
        const infuraKey = process.env.INFURA_KEY;
        return new HDWalletProvider(privateKey, `https://sepolia.infura.io/v3/${infuraKey}`);
      },
      network_id: 11155111,
      gas: 4465030,
      gasPrice: 10000000000,
    },
  },

  // Solidity compiler configuration
  compilers: {
    solc: {
      version: "0.8.19",
      settings: {
        optimizer: {
          enabled: true,
          runs: 200,
        },
      },
    },
  },

  // Mocha test configuration
  mocha: {
    timeout: 100000,
  },

  // Plugins configuration
  plugins: [
    'truffle-plugin-verify',
    'truffle-contract-size',
    'solidity-coverage',
  ],

  // API keys for plugins
  api_keys: {
    etherscan: process.env.ETHERSCAN_API_KEY,
  },

  // Verify contracts after deployment
  verify: {
    etherscan: {
      apiKey: process.env.ETHERSCAN_API_KEY,
    },
  },
};

// ===== contracts/Storage.sol =====
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract Storage {
    uint256 private number;
    string private message;
    address public owner;

    event DataStored(uint256 indexed newValue, string indexed newMessage, address indexed storedBy);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event MessageUpdated(string indexed oldMessage, string indexed newMessage);

    constructor(uint256 _initialNumber, string memory _initialMessage) {
        number = _initialNumber;
        message = _initialMessage;
        owner = msg.sender;
        emit DataStored(_initialNumber, _initialMessage, msg.sender);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Storage: caller is not the owner");
        _;
    }

    function store(uint256 _num, string memory _msg) public onlyOwner {
        uint256 oldValue = number;
        string memory oldMessage = message;

        number = _num;
        message = _msg;

        emit DataStored(_num, _msg, msg.sender);
        emit MessageUpdated(oldMessage, _msg);
    }

    function retrieve() public view returns (uint256, string memory) {
        return (number, message);
    }

    function getNumber() public view returns (uint256) {
        return number;
    }

    function getMessage() public view returns (string memory) {
        return message;
    }

    function transferOwnership(address _newOwner) public onlyOwner {
        require(_newOwner != address(0), "Storage: new owner is the zero address");
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
    }
}

// ===== test/storage.test.js =====
const { expect } = require('chai');
const { ethers } = require('hardhat');

describe('Storage Contract', function () {
    let storage;
    let owner;
    let addr1;
    let addr2;

    beforeEach(async function () {
        [owner, addr1, addr2] = await ethers.getSigners();

        const Storage = await ethers.getContractFactory('Storage');
        storage = await Storage.deploy(42, "Hello, Truffle!");
        await storage.deployed();
    });

    describe('Deployment', function () {
        it('Should set the right owner', async function () {
            expect(await storage.owner()).to.equal(owner.address);
        });

        it('Should set the initial number', async function () {
            const [number] = await storage.retrieve();
            expect(number).to.equal(42);
        });

        it('Should set the initial message', async function () {
            const [, message] = await storage.retrieve();
            expect(message).to.equal("Hello, Truffle!");
        });

        it('Should emit DataStored event on deployment', async function () {
            await expect(storage.deployTransaction)
                .to.emit(storage, 'DataStored')
                .withArgs(42, "Hello, Truffle!", owner.address);
        });
    });

    describe('Store function', function () {
        it('Should allow owner to store new values', async function () {
            await storage.store(100, "New message");
            const [number, message] = await storage.retrieve();
            expect(number).to.equal(100);
            expect(message).to.equal("New message");
        });

        it('Should emit DataStored event when storing', async function () {
            await expect(storage.store(100, "New message"))
                .to.emit(storage, 'DataStored')
                .withArgs(100, "New message", owner.address);
        });

        it('Should emit MessageUpdated event when storing', async function () {
            await expect(storage.store(100, "New message"))
                .to.emit(storage, 'MessageUpdated')
                .withArgs("Hello, Truffle!", "New message");
        });

        it('Should not allow non-owner to store values', async function () {
            await expect(
                storage.connect(addr1).store(100, "Unauthorized")
            ).to.be.revertedWith('Storage: caller is not the owner');
        });
    });

    describe('Get functions', function () {
        it('Should return correct number', async function () {
            expect(await storage.getNumber()).to.equal(42);
        });

        it('Should return correct message', async function () {
            expect(await storage.getMessage()).to.equal("Hello, Truffle!");
        });
    });

    describe('Ownership transfer', function () {
        it('Should allow owner to transfer ownership', async function () {
            await storage.transferOwnership(addr1.address);
            expect(await storage.owner()).to.equal(addr1.address);
        });

        it('Should emit OwnershipTransferred event', async function () {
            await expect(storage.transferOwnership(addr1.address))
                .to.emit(storage, 'OwnershipTransferred')
                .withArgs(owner.address, addr1.address);
        });

        it('Should not allow transfer to zero address', async function () {
            await expect(
                storage.transferOwnership(ethers.constants.AddressZero)
            ).to.be.revertedWith('Storage: new owner is the zero address');
        });

        it('Should allow new owner to store values', async function () {
            await storage.transferOwnership(addr1.address);
            await storage.connect(addr1).store(200, "New owner message");

            const [number, message] = await storage.retrieve();
            expect(number).to.equal(200);
            expect(message).to.equal("New owner message");
        });

        it('Should not allow old owner to store after transfer', async function () {
            await storage.transferOwnership(addr1.address);
            await expect(
                storage.store(300, "Old owner message")
            ).to.be.revertedWith('Storage: caller is not the owner');
        });
    });

    describe('Edge cases', function () {
        it('Should handle zero values', async function () {
            await storage.store(0, "");
            const [number, message] = await storage.retrieve();
            expect(number).to.equal(0);
            expect(message).to.equal("");
        });

        it('Should handle large values', async function () {
            const largeNumber = ethers.constants.MaxUint256;
            await storage.store(largeNumber, "Maximum value");
            const [number] = await storage.retrieve();
            expect(number).to.equal(largeNumber);
        });
    });
});

// ===== migrations/1_initial_migration.js =====
const Migrations = artifacts.require("Migrations");

module.exports = function (deployer) {
  deployer.deploy(Migrations);
};

// ===== migrations/2_deploy_storage.js =====
const Storage = artifacts.require("Storage");

module.exports = function (deployer) {
  // Deploy with initial values
  deployer.deploy(Storage, 42, "Hello, Truffle!");
};

// ===== scripts/deploy.js =====
const Storage = artifacts.require("Storage");

async function main() {
  console.log("Starting deployment...");

  // Get deployer account
  const accounts = await web3.eth.getAccounts();
  const deployer = accounts[0];
  console.log("Deploying contracts with account:", deployer);

  // Get account balance
  const balance = await web3.eth.getBalance(deployer);
  console.log("Account balance:", web3.utils.fromWei(balance, "ether"), "ETH");

  // Deploy Storage contract
  console.log("Deploying Storage contract...");
  const storage = await Storage.new(100, "Initial deployment message", {
    from: deployer,
    gas: 2000000,
    gasPrice: web3.utils.toWei("20", "gwei"),
  });

  console.log("Storage contract deployed to:", storage.address);

  // Verify deployment
  const [number, message] = await storage.retrieve();
  console.log("Initial values:");
  console.log("  Number:", number.toString());
  console.log("  Message:", message);

  console.log("Deployment completed successfully!");
  return storage;
}

// For use with truffle exec
if (typeof module !== 'undefined' && module.exports) {
  module.exports = function(callback) {
    main().then(() => callback()).catch(err => callback(err));
  };
}

// ===== scripts/interact.js =====
const Storage = artifacts.require("Storage");

async function main() {
  console.log("Contract Interaction Example");
  console.log("==========================");

  // Get deployed contract
  const storage = await Storage.deployed();
  console.log("Storage contract address:", storage.address);

  // Get current values
  const [number, message] = await storage.retrieve();
  console.log("\nCurrent values:");
  console.log("  Number:", number.toString());
  console.log("  Message:", message);

  // Store new values
  console.log("\nStoring new values...");
  const tx = await storage.store(200, "Updated via script");
  console.log("Transaction hash:", tx.tx);
  console.log("Gas used:", tx.receipt.gasUsed.toString());

  // Verify updated values
  const [newNumber, newMessage] = await storage.retrieve();
  console.log("\nUpdated values:");
  console.log("  Number:", newNumber.toString());
  console.log("  Message:", newMessage);

  // Get contract owner
  const owner = await storage.owner();
  console.log("\nContract owner:", owner);

  console.log("\nInteraction completed!");
}

// For use with truffle exec
if (typeof module !== 'undefined' && module.exports) {
  module.exports = function(callback) {
    main().then(() => callback()).catch(err => callback(err));
  };
}

// ===== package.json =====
{
  "name": "truffle-hello-world",
  "version": "1.0.0",
  "description": "Truffle Hello World example project",
  "main": "truffle-config.js",
  "scripts": {
    "compile": "truffle compile",
    "migrate": "truffle migrate",
    "test": "truffle test",
    "dev": "truffle migrate --network development",
    "goerli": "truffle migrate --network goerli",
    "sepolia": "truffle migrate --network sepolia",
    "verify": "truffle run verify Storage --network sepolia",
    "console": "truffle console",
    "coverage": "truffle run coverage"
  },
  "dependencies": {
    "@truffle/hdwallet-provider": "^2.1.15",
    "@openzeppelin/contracts": "^4.9.0",
    "ethereumjs-wallet": "^1.0.2"
  },
  "devDependencies": {
    "chai": "^4.3.8",
    "solidity-coverage": "^0.8.4",
    "truffle-plugin-verify": "^0.6.4",
    "truffle-contract-size": "^2.0.1"
  }
}

💻 Testes Avançados Truffle javascript

🟡 intermediate ⭐⭐⭐⭐

Estratégias de teste abrangentes incluindo testes unitários, de integração, otimização de gás e utilitários de teste personalizados

⏱️ 35 min 🏷️ truffle, testing, smart contracts, gas
Prerequisites: Truffle basics, Chai assertion library, Understanding of smart contract testing
// Truffle Advanced Testing Suite
// Comprehensive testing patterns for smart contracts

const { expect } = require('chai');
const { ethers } = require('hardhat');
const { time } = require('@openzeppelin/test-helpers');

// ===== Test Utilities =====
class ContractTestHelper {
  constructor(contract) {
    this.contract = contract;
  }

  // Revert expectation helper
  async expectRevert(promise, expectedError) {
    await expect(promise).to.be.revertedWith(expectedError);
  }

  // Event emission helper
  async expectEvent(promise, eventName, ...args) {
    const tx = await promise;
    await expect(tx).to.emit(this.contract, eventName);
    if (args.length > 0) {
      await expect(tx).to.emit(this.contract, eventName).withArgs(...args);
    }
    return tx;
  }

  // Balance change helper
  async expectBalanceChange(account, change) {
    const before = await ethers.provider.getBalance(account);
    const result = await this.contract.deployTransaction;
    const receipt = await result.wait();
    const after = await ethers.provider.getBalance(account);

    const actualChange = after.sub(before);
    expect(actualChange).to.equal(change);
  }

  // Gas usage helper
  async measureGas(transactionFunction) {
    const tx = await transactionFunction();
    const receipt = await tx.wait();
    return receipt.gasUsed.toString();
  }

  // Time helper for time-dependent contracts
  async increaseTime(seconds) {
    await ethers.provider.send('evm_increaseTime', [seconds]);
    await ethers.provider.send('evm_mine');
  }

  // Mine blocks helper
  async mineBlocks(count) {
    for (let i = 0; i < count; i++) {
      await ethers.provider.send('evm_mine');
    }
  }
}

// ===== test/advanced/Storage.advanced.test.js =====
describe('Storage Contract - Advanced Testing', function () {
    let storage;
    let owner, addr1, addr2, addrs;
    let helper;

    beforeEach(async function () {
        [owner, addr1, addr2, ...addrs] = await ethers.getSigners();

        const Storage = await ethers.getContractFactory('Storage');
        storage = await Storage.deploy(42, "Initial message");
        await storage.deployed();

        helper = new ContractTestHelper(storage);
    });

    describe('State Testing', function () {
        it('Should maintain consistent state across operations', async function () {
            // Initial state
            const initialNumber = await storage.getNumber();
            const initialMessage = await storage.getMessage();

            expect(initialNumber).to.equal(42);
            expect(initialMessage).to.equal("Initial message");

            // State change
            await storage.store(100, "Updated message");

            // Verify new state
            const newNumber = await storage.getNumber();
            const newMessage = await storage.getMessage();

            expect(newNumber).to.equal(100);
            expect(newMessage).to.equal("Updated message");

            // State should persist
            const [number, message] = await storage.retrieve();
            expect(number).to.equal(100);
            expect(message).to.equal("Updated message");
        });

        it('Should handle boundary values correctly', async function () {
            // Test with zero
            await storage.store(0, "");
            let [number, message] = await storage.retrieve();
            expect(number).to.equal(0);
            expect(message).to.equal("");

            // Test with maximum uint256
            const maxUint256 = ethers.constants.MaxUint256;
            await storage.store(maxUint256, "Max value");
            [number, message] = await storage.retrieve();
            expect(number).to.equal(maxUint256);
            expect(message).to.equal("Max value");
        });
    });

    describe('Access Control Testing', function () {
        it('Should enforce ownership restrictions', async function () {
            // Owner can call restricted functions
            await expect(storage.store(1, "Owner test")).to.not.be.reverted;

            // Non-owners cannot call restricted functions
            await expect(
                storage.connect(addr1).store(1, "Non-owner test")
            ).to.be.revertedWith('Storage: caller is not the owner');

            // After ownership transfer, new owner can call
            await storage.transferOwnership(addr1.address);
            await expect(
                storage.connect(addr1).store(2, "New owner test")
            ).to.not.be.reverted;

            // Old owner cannot call after transfer
            await expect(
                storage.store(3, "Old owner test")
            ).to.be.revertedWith('Storage: caller is not the owner');
        });
    });

    describe('Event Testing', function () {
        it('Should emit correct events with proper parameters', async function () {
            // Test DataStored event
            await expect(storage.store(100, "Test message"))
                .to.emit(storage, 'DataStored')
                .withArgs(100, "Test message", owner.address);

            // Test MessageUpdated event
            await expect(storage.store(200, "New test"))
                .to.emit(storage, 'MessageUpdated')
                .withArgs("Test message", "New test");

            // Test OwnershipTransferred event
            await expect(storage.transferOwnership(addr1.address))
                .to.emit(storage, 'OwnershipTransferred')
                .withArgs(owner.address, addr1.address);
        });
    });

    describe('Gas Optimization Testing', function () {
        it('Should measure gas consumption for different operations', async function () {
            // Measure deployment gas
            const deployGas = await helper.measureGas(async () => {
                const Storage = await ethers.getContractFactory('Storage');
                return await Storage.deploy(42, "Test");
            });
            console.log('Deployment gas:', deployGas);

            // Measure store operation gas
            const storeGas = await helper.measureGas(async () => {
                return await storage.store(100, "Gas test message");
            });
            console.log('Store operation gas:', storeGas);

            // Measure retrieve operation gas
            const retrieveGas = await helper.measureGas(async () => {
                return await storage.retrieve();
            });
            console.log('Retrieve operation gas:', retrieveGas);

            // Measure transfer ownership gas
            const transferGas = await helper.measureGas(async () => {
                return await storage.transferOwnership(addr1.address);
            });
            console.log('Transfer ownership gas:', transferGas);

            // Assertions for gas efficiency
            expect(parseInt(storeGas)).to.be.lessThan(100000);
            expect(parseInt(retrieveGas)).to.be.lessThan(50000);
        });
    });

    describe('Integration Testing', function () {
        it('Should work correctly with multiple accounts', async function () {
            // Deploy with one account
            const deployer = owner;
            expect(await storage.owner()).to.equal(deployer.address);

            // Transfer to another account
            await storage.transferOwnership(addr1.address);
            expect(await storage.owner()).to.equal(addr1.address);

            // New owner performs operations
            await storage.connect(addr1).store(300, "Multi-account test");
            const [number, message] = await storage.retrieve();
            expect(number).to.equal(300);
            expect(message).to.equal("Multi-account test");

            // Original account should no longer have access
            await expect(
                storage.store(400, "Should fail")
            ).to.be.revertedWith('Storage: caller is not the owner');
        });
    });

    describe('Error Handling Testing', function () {
        it('Should handle error conditions gracefully', async function () {
            // Test unauthorized access
            await expect(
                storage.connect(addr1).store(1, "Unauthorized")
            ).to.be.revertedWith('Storage: caller is not the owner');

            // Test invalid ownership transfer
            await expect(
                storage.transferOwnership(ethers.constants.AddressZero)
            ).to.be.revertedWith('Storage: new owner is the zero address');
        });
    });

    describe('Fuzz Testing', function () {
        it('Should handle random inputs correctly', async function () {
            const testCases = [
                { number: 0, message: "" },
                { number: 1, message: "1" },
                { number: ethers.constants.MaxUint256, message: "A".repeat(1000) },
                { number: 12345, message: "Random message 🚀" },
                { number: 0, message: "Zero number test" },
            ];

            for (const testCase of testCases) {
                await storage.store(testCase.number, testCase.message);
                const [number, message] = await storage.retrieve();

                expect(number).to.equal(testCase.number);
                expect(message).to.equal(testCase.message);
            }
        });
    });
});

// ===== test/advanced/GasProfiler.js =====
class GasProfiler {
    constructor() {
        this.measurements = [];
    }

    async measureFunction(contract, functionName, args = [], description = '') {
        const tx = await contract[functionName](...args);
        const receipt = await tx.wait();

        const measurement = {
            description: description || functionName,
            functionName,
            gasUsed: receipt.gasUsed.toString(),
            transactionHash: tx.hash,
            timestamp: new Date().toISOString(),
        };

        this.measurements.push(measurement);
        console.log(`⛽ ${measurement.description}: ${measurement.gasUsed} gas`);

        return measurement;
    }

    getMeasurements() {
        return this.measurements;
    }

    exportMeasurements() {
        return {
            timestamp: new Date().toISOString(),
            measurements: this.measurements,
            totalGasUsed: this.measurements.reduce((sum, m) => sum + parseInt(m.gasUsed), 0),
            averageGasUsed: Math.round(
                this.measurements.reduce((sum, m) => sum + parseInt(m.gasUsed), 0) /
                this.measurements.length
            ),
        };
    }

    generateReport() {
        const report = this.exportMeasurements();

        console.log('\n=== Gas Profiling Report ===');
        console.log(`Total measurements: ${this.measurements.length}`);
        console.log(`Total gas used: ${report.totalGasUsed.toLocaleString()}`);
        console.log(`Average gas per operation: ${report.averageGasUsed.toLocaleString()}`);
        console.log('\nDetailed measurements:');

        this.measurements.forEach((m, i) => {
            console.log(`${i + 1}. ${m.description}: ${parseInt(m.gasUsed).toLocaleString()} gas`);
        });

        return report;
    }
}

// Usage in tests
describe('Gas Profiling', function () {
    let storage, profiler;

    beforeEach(async function () {
        const Storage = await ethers.getContractFactory('Storage');
        storage = await Storage.deploy(42, "Test");
        await storage.deployed();
        profiler = new GasProfiler();
    });

    it('Should profile gas usage', async function () {
        await profiler.measureFunction(storage, 'store', [100, "Test 1"], "Store operation 1");
        await profiler.measureFunction(storage, 'retrieve', [], "Retrieve operation");
        await profiler.measureFunction(storage, 'store', [200, "Test 2"], "Store operation 2");
        await profiler.measureFunction(storage, 'transferOwnership', [addr1.address], "Transfer ownership");

        const report = profiler.generateReport();

        // Assertions for gas efficiency
        expect(report.averageGasUsed).to.be.lessThan(100000);
    });
});

// ===== test/hooks/beforeEach.js =====
// Global test setup and teardown
const { expect } = require('chai');

// Test timeout helper
const testTimeout = (ms) => {
    return new Promise(resolve => setTimeout(resolve, ms));
};

// Clean revert helper
const cleanRevert = async (promise) => {
    try {
        await promise;
        throw new Error('Expected revert but transaction succeeded');
    } catch (error) {
        expect(error.message).to.include('revert');
    }
};

// Snapshot helper for EVM state
const takeSnapshot = async () => {
    return await ethers.provider.send('evm_snapshot', []);
};

const revertToSnapshot = async (snapshotId) => {
    await ethers.provider.send('evm_revert', [snapshotId]);
};

// Global setup
before(async function () {
    this.timeout(60000); // Increase timeout for network tests

    // Log test environment
    const network = await ethers.provider.getNetwork();
    console.log(`Testing on network: ${network.name} (Chain ID: ${network.chainId})`);

    // Get accounts
    const accounts = await ethers.provider.listAccounts();
    console.log(`Testing with ${accounts.length} accounts`);
});

// Global teardown
after(async function () {
    console.log('All tests completed');
});

💻 Scripts e Estratégias de Implantação Truffle javascript

🟡 intermediate ⭐⭐⭐⭐

Scripts de implantação prontos para produção incluindo verificação, otimização de gás, contratos atualizáveis e implantação multi-rede

⏱️ 40 min 🏷️ truffle, deployment, production, optimization
Prerequisites: Truffle experience, Understanding of contract deployment, Gas optimization knowledge
// Truffle Deployment Scripts and Strategies
// Production-ready deployment automation

// ===== scripts/deployWithVerification.js =====
const Storage = artifacts.require("Storage");
const { expect } = require('chai');

async function main() {
    console.log("🚀 Starting Deployment with Verification");
    console.log("=====================================");

    // Get network information
    const network = await web3.eth.net.getId();
    console.log(`Deploying to network: ${network}`);

    // Get deployer account
    const accounts = await web3.eth.getAccounts();
    const deployer = accounts[0];
    console.log(`Deployer address: ${deployer}`);

    // Check account balance
    const balance = await web3.eth.getBalance(deployer);
    const balanceEth = web3.utils.fromWei(balance, 'ether');
    console.log(`Account balance: ${balanceEth} ETH`);

    if (parseFloat(balanceEth) < 0.1) {
        console.warn("⚠️  Warning: Low account balance for deployment");
    }

    // Gas price estimation
    const gasPrice = await web3.eth.getGasPrice();
    const gasPriceGwei = web3.utils.fromWei(gasPrice, 'gwei');
    console.log(`Current gas price: ${gasPriceGwei} gwei`);

    try {
        // Deploy contract
        console.log("\n📦 Deploying Storage contract...");

        const estimatedGas = await Storage.deploy.estimateGas(42, "Hello, Production!");
        console.log(`Estimated gas: ${estimatedGas}`);

        const storage = await Storage.new(42, "Hello, Production!", {
            from: deployer,
            gas: Math.floor(estimatedGas * 1.2), // 20% buffer
            gasPrice: gasPrice,
        });

        console.log(`✅ Storage contract deployed to: ${storage.address}`);

        // Wait for a few confirmations
        console.log("⏳ Waiting for confirmations...");
        await new Promise(resolve => setTimeout(resolve, 3000));

        // Verify deployment
        const [number, message] = await storage.retrieve();
        console.log(`📋 Contract initialized with:`);
        console.log(`   Number: ${number}`);
        console.log(`   Message: ${message}`);

        // Contract verification (if supported)
        if (network !== 1337 && network !== 31337) { // Not development networks
            console.log("\n🔍 Verifying contract on Etherscan...");
            try {
                await run('verify:verify', {
                    address: storage.address,
                    constructorArguments: [42, "Hello, Production!"],
                });
                console.log("✅ Contract verified on Etherscan");
            } catch (error) {
                console.log("❌ Contract verification failed:", error.message);
            }
        }

        // Save deployment info
        const deploymentInfo = {
            network: network,
            contract: "Storage",
            address: storage.address,
            deployer: deployer,
            gasUsed: storage.deployTransaction.gasUsed,
            gasPrice: gasPrice,
            transactionHash: storage.deployTransaction.transactionHash,
            blockNumber: storage.deployTransaction.blockNumber,
            timestamp: new Date().toISOString(),
        };

        console.log("\n📄 Deployment Summary:");
        console.log(JSON.stringify(deploymentInfo, null, 2));

        return deploymentInfo;

    } catch (error) {
        console.error("❌ Deployment failed:", error);
        throw error;
    }
}

// Export for truffle exec
module.exports = function(callback) {
    main()
        .then(() => callback())
        .catch(err => callback(err));
};

// ===== scripts/upgradeableDeployment.js =====
// OpenZeppelin upgradeable contracts deployment
const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');
const StorageV1 = artifacts.require('StorageV1');
const StorageV2 = artifacts.require('StorageV2');

async function deployV1() {
    console.log("🚀 Deploying Storage V1 (Upgradeable)");

    const storage = await deployProxy(StorageV1, [42, "Hello, V1!"], {
        initializer: 'initialize',
    });

    console.log(`Storage V1 deployed to: ${storage.address}`);

    // Test initial functionality
    const [number, message] = await storage.retrieve();
    console.log(`Initial values - Number: ${number}, Message: ${message}`);

    return storage;
}

async function upgradeToV2() {
    console.log("🔄 Upgrading to Storage V2");

    const existing = await StorageV1.deployed();
    const upgraded = await upgradeProxy(existing.address, StorageV2);

    console.log(`Storage upgraded to V2 at: ${upgraded.address}`);

    // Test new functionality
    await upgraded.setAdditionalData("Additional V2 feature");
    const additionalData = await upgraded.getAdditionalData();
    console.log(`Additional data: ${additionalData}`);

    return upgraded;
}

// ===== scripts/multiNetworkDeployment.js =====
const Storage = artifacts.require("Storage");

// Network configurations
const NETWORKS = {
    development: {
        name: "Development",
        gasLimit: 8000000,
        gasPrice: 20000000000, // 20 gwei
    },
    goerli: {
        name: "Goerli Testnet",
        gasLimit: 6000000,
        gasPrice: 20000000000, // 20 gwei
        confirmations: 2,
    },
    sepolia: {
        name: "Sepolia Testnet",
        gasLimit: 6000000,
        gasPrice: 20000000000, // 20 gwei
        confirmations: 2,
    },
    mainnet: {
        name: "Ethereum Mainnet",
        gasLimit: 8000000,
        gasPrice: 30000000000, // 30 gwei
        confirmations: 5,
    },
};

async function deployToNetwork(networkName) {
    const networkConfig = NETWORKS[networkName];
    if (!networkConfig) {
        throw new Error(`Network ${networkName} not configured`);
    }

    console.log(`🌐 Deploying to ${networkConfig.name}`);

    const network = await web3.eth.net.getId();
    const accounts = await web3.eth.getAccounts();
    const deployer = accounts[0];

    console.log(`Deployer: ${deployer}`);

    const balance = await web3.eth.getBalance(deployer);
    console.log(`Balance: ${web3.utils.fromWei(balance, 'ether')} ETH`);

    // Get current gas price for mainnet
    let gasPrice = networkConfig.gasPrice;
    if (networkName === 'mainnet') {
        gasPrice = await web3.eth.getGasPrice();
        console.log(`Current gas price: ${web3.utils.fromWei(gasPrice, 'gwei')} gwei`);
    }

    try {
        const storage = await Storage.new(42, "Multi-network deployment", {
            from: deployer,
            gas: networkConfig.gasLimit,
            gasPrice: gasPrice,
        });

        console.log(`✅ Deployed to: ${storage.address}`);

        // Wait for confirmations on testnets/mainnet
        if (networkConfig.confirmations > 0) {
            console.log(`⏳ Waiting for ${networkConfig.confirmations} confirmations...`);

            for (let i = 0; i < networkConfig.confirmations; i++) {
                await new Promise(resolve => setTimeout(resolve, 15000)); // 15 seconds per block
                console.log(`Confirmation ${i + 1}/${networkConfig.confirmations}`);
            }
        }

        // Verify deployment
        const [number, message] = await storage.retrieve();
        console.log(`✅ Verification successful - Number: ${number}, Message: ${message}`);

        return {
            network: networkName,
            address: storage.address,
            transactionHash: storage.deployTransaction.transactionHash,
        };

    } catch (error) {
        console.error(`❌ Deployment to ${networkName} failed:`, error);
        throw error;
    }
}

async function deployToAllNetworks() {
    const deployments = {};
    const currentNetwork = await web3.eth.net.getId();

    for (const networkName of Object.keys(NETWORKS)) {
        try {
            // Skip if we're not on the right network
            if (currentNetwork !== 1337 && networkName === 'development') continue;

            const deployment = await deployToNetwork(networkName);
            deployments[networkName] = deployment;

            console.log(`✅ ${networkName}: ${deployment.address}`);

        } catch (error) {
            console.error(`❌ ${networkName}: Deployment failed`);
            deployments[networkName] = { error: error.message };
        }
    }

    console.log("\n📊 Deployment Summary:");
    console.log(JSON.stringify(deployments, null, 2));

    return deployments;
}

// ===== scripts/gasOptimization.js =====
const Storage = artifacts.require("Storage");

class GasOptimizer {
    constructor() {
        this.measurements = [];
    }

    async optimizeGasPrice() {
        const currentGasPrice = await web3.eth.getGasPrice();
        const recommendedGasPrice = Math.floor(currentGasPrice * 0.9); // 10% less

        console.log(`Current gas price: ${web3.utils.fromWei(currentGasPrice, 'gwei')} gwei`);
        console.log(`Recommended: ${web3.utils.fromWei(recommendedGasPrice, 'gwei')} gwei`);

        return recommendedGasPrice;
    }

    async estimateDeploymentGas(contractName, constructorArgs) {
        const Contract = artifacts.require(contractName);

        try {
            const estimatedGas = await Contract.deploy.estimateGas(...constructorArgs);
            const bufferedGas = Math.floor(estimatedGas * 1.1); // 10% buffer

            console.log(`Estimated gas for ${contractName}: ${estimatedGas}`);
            console.log(`With 10% buffer: ${bufferedGas}`);

            return { estimated: estimatedGas, buffered: bufferedGas };
        } catch (error) {
            console.error(`Gas estimation failed for ${contractName}:`, error);
            return null;
        }
    }

    async deployWithGasOptimization(contractName, constructorArgs = [], options = {}) {
        console.log(`⛡️  Optimizing deployment for ${contractName}`);

        // Get optimized gas price
        const optimizedGasPrice = await this.optimizeGasPrice();

        // Estimate gas usage
        const gasEstimate = await this.estimateDeploymentGas(contractName, constructorArgs);

        if (!gasEstimate) {
            throw new Error(`Failed to estimate gas for ${contractName}`);
        }

        const Contract = artifacts.require(contractName);

        // Deploy with optimized parameters
        const deployOptions = {
            gas: gasEstimate.buffered,
            gasPrice: optimizedGasPrice,
            ...options,
        };

        console.log(`📦 Deploying ${contractName} with optimized gas settings...`);

        const startTime = Date.now();
        const contract = await Contract.new(...constructorArgs, deployOptions);
        const endTime = Date.now();

        const deploymentTime = endTime - startTime;
        const deploymentCost = web3.utils.fromWei(
            (gasEstimate.buffered * optimizedGasPrice).toString(),
            'ether'
        );

        console.log(`✅ ${contractName} deployed to: ${contract.address}`);
        console.log(`⏱️  Deployment time: ${deploymentTime}ms`);
        console.log(`💰 Deployment cost: ${deploymentCost} ETH`);

        // Store measurement
        this.measurements.push({
            contract: contractName,
            address: contract.address,
            gasUsed: contract.deployTransaction.gasUsed.toString(),
            gasPrice: optimizedGasPrice.toString(),
            cost: deploymentCost,
            time: deploymentTime,
            timestamp: new Date().toISOString(),
        });

        return contract;
    }

    getOptimizationReport() {
        const totalCost = this.measurements.reduce((sum, m) => sum + parseFloat(m.cost), 0);
        const avgGasPrice = this.measurements.reduce((sum, m) =>
            sum + parseInt(m.gasPrice), 0) / this.measurements.length;

        return {
            deployments: this.measurements.length,
            totalCost: totalCost.toFixed(6),
            averageGasPrice: web3.utils.fromWei(avgGasPrice.toFixed(0), 'gwei'),
            deployments: this.measurements,
        };
    }
}

// Usage example
async function deployWithOptimization() {
    const optimizer = new GasOptimizer();

    // Deploy multiple contracts with optimization
    await optimizer.deployWithGasOptimization('Storage', [100, "Gas optimized"]);

    const report = optimizer.getOptimizationReport();
    console.log("\n📊 Gas Optimization Report:");
    console.log(JSON.stringify(report, null, 2));
}

// Export for truffle exec
module.exports = function(callback) {
    deployWithOptimization()
        .then(() => callback())
        .catch(err => callback(err));
};

// ===== scripts/deploymentManager.js =====
class DeploymentManager {
    constructor() {
        this.deployments = new Map();
        this.dependencies = new Map();
    }

    addDependency(contractName, dependencyNames = []) {
        this.dependencies.set(contractName, dependencyNames);
    }

    async deploySequential() {
        console.log("🔗 Starting sequential deployment");

        const deployedContracts = {};

        // Simple dependency resolution (would need more complex algorithm for real use)
        for (const [contractName, dependencies] of this.dependencies) {
            console.log(`\n📦 Deploying ${contractName}`);

            // Check if dependencies are deployed
            for (const dep of dependencies) {
                if (!deployedContracts[dep]) {
                    throw new Error(`Dependency ${dep} not deployed for ${contractName}`);
                }
            }

            // Deploy contract (simplified example)
            const Contract = artifacts.require(contractName);
            const contract = await Contract.new();

            deployedContracts[contractName] = contract;
            this.deployments.set(contractName, {
                address: contract.address,
                transactionHash: contract.deployTransaction.transactionHash,
            });

            console.log(`✅ ${contractName} deployed to: ${contract.address}`);
        }

        return deployedContracts;
    }

    async verifyDeployments() {
        console.log("\n🔍 Verifying all deployments");

        for (const [contractName, deployment] of this.deployments) {
            try {
                const Contract = artifacts.require(contractName);
                const contract = await Contract.at(deployment.address);

                // Basic verification - would need contract-specific tests
                console.log(`✅ ${contractName} at ${deployment.address} is verified`);
            } catch (error) {
                console.error(`❌ ${contractName} verification failed:`, error.message);
            }
        }
    }

    exportDeploymentManifest() {
        const manifest = {
            version: "1.0.0",
            timestamp: new Date().toISOString(),
            network: await web3.eth.net.getId(),
            deployments: Object.fromEntries(this.deployments),
            dependencies: Object.fromEntries(this.dependencies),
        };

        console.log("\n📄 Deployment Manifest:");
        console.log(JSON.stringify(manifest, null, 2));

        return manifest;
    }
}

// Usage example
async function manageDeployment() {
    const manager = new DeploymentManager();

    // Define deployment dependencies
    manager.addDependency('Storage', []);
    manager.addDependency('StorageManager', ['Storage']);
    manager.addDependency('StorageFactory', ['Storage', 'StorageManager']);

    // Execute deployment
    await manager.deploySequential();

    // Verify deployments
    await manager.verifyDeployments();

    // Export manifest
    manager.exportDeploymentManifest();
}

// Export for truffle exec
module.exports = function(callback) {
    manageDeployment()
        .then(() => callback())
        .catch(err => callback(err));
};