export { ChannelClient, VOUCHER_TYPES, getVoucherDomain, signVoucher } from './chunk-OSPRJZ5T.js';
export { CommunityClient, UserLifecycle } from './chunk-YHM77LIP.js';
export { UserClient } from './chunk-DI3E6PMI.js';
export { OperatorLifecycle, PaymasterOperatorClient, ProposalState, ProtocolClient } from './chunk-O3Y7II3B.js';
export { ProtocolGovernance } from './chunk-4DVUM4MC.js';
export { dist_exports as AirAccount } from './chunk-4KRQXOTI.js';
export { UserOpClient, createEOAWalletClient, getUserOpHash, packUserOpLimits, toSimpleSmartAccount } from './chunk-HVAB4TTT.js';
export { ReputationClient, checkMySBT, getMySBTId } from './chunk-NZGXB2C5.js';
export { FinanceClient } from './chunk-PCLPYRTX.js';
export { AirAccountEIP1193Provider, DVTClient, announceAirAccount, useCreditScore, useSuperPaymaster, watchProviders } from './chunk-6JCYPTSH.js';
export { PaymasterClient, PaymasterManager, PaymasterOperator, SuperPaymasterAdminClient, SuperPaymasterClient, buildPaymasterData, buildSuperPaymasterData, checkEligibility, formatUserOpV07, getPaymasterV4Middleware, getSuperPaymasterMiddleware, getUserOpHashV07, tuneGasLimit } from './chunk-MPOMWT2J.js';
export { EIP3009_TYPES, FacilitatorClient, GTOKEN_EIP712_DOMAIN, HEADER_PAYMENT_REQUIRED, HEADER_PAYMENT_RESPONSE, HEADER_PAYMENT_SIGNATURE, HEADER_V1_PAYMENT, HEADER_V1_PAYMENT_RESPONSE, X402Client, decodePaymentPayload, decodePaymentRequired, decodeSettleResponse, encodePaymentPayload, encodePaymentRequired, encodeSettleResponse, extractPaymentRequired, extractSettleResponse, generateNonce, getEIP3009Domain, signCancelAuthorization, signGTokenTransferWithAuthorization, signReceiveWithAuthorization, signTransferWithAuthorization } from './chunk-XFI3AK32.js';
import { paymasterActions, superPaymasterActions, sbtActions, registryActions, RegistryABI, stakingActions, aggregatorActions, xPNTsFactoryActions, dvtActions, SuperPaymasterABI, xPNTsTokenABI, PaymasterFactoryABI } from './chunk-ZSSNU3UF.js';
export { AASTAR_COMMUNITY, AAStarAirAccountFactoryV7ABI, AAStarAirAccountFactoryV7Artifact, AAStarAirAccountV7ABI, AAStarAirAccountV7Artifact, AAStarBLSAggregatorABI, AAStarBLSAggregatorArtifact, AAStarBLSAlgorithmABI, AAStarBLSAlgorithmArtifact, AAStarValidatorABI, AAStarValidatorArtifact, ALL_ROLES, AgentRegistryABI, AgentRegistryArtifact, AirAccountDelegateABI, AirAccountDelegateArtifact, AirAccountExtensionABI, AirAccountExtensionArtifact, AuthorizationState, BLSAggregatorABI, BLSAggregatorArtifact, BLSHelpers, BLSSigner, BLSValidatorABI, BLSValidatorArtifact, BLS_POP_DST, BRANDING, BREAD_COMMUNITY, BaseClient, BundlerClient, COMMUNITIES, CONTRACTS, CONTRACT_METADATA, CalldataParserRegistryABI, CalldataParserRegistryArtifact, ContractConfigManager, DEFAULT_ADMIN_ROLE, DVTValidatorABI, DVTValidatorArtifact, DVT_TIER_T2, DVT_TIER_T3, EntryPointABI, EntryPointArtifact, EntryPointVersion, ForceExitModuleABI, ForceExitModuleArtifact, GTokenABI, GTokenArtifact, GTokenAuthorizationABI, GTokenAuthorizationArtifact, GTokenStakingABI, GTokenStakingArtifact, INITIAL_ROLE_STAKES, LINKS, MicroPaymentChannelABI, MicroPaymentChannelArtifact, MySBTABI, MySBTArtifact, NETWORKS, NodeType, PaymasterABI, PaymasterArtifact, PaymasterFactoryABI, PaymasterFactoryArtifact, PolicyDecision, PolicyRegistryABI, PolicyRegistryArtifact, ROLE_ANODE, ROLE_COMMUNITY, ROLE_DVT, ROLE_ENDUSER, ROLE_KMS, ROLE_NAMES, ROLE_PAYMASTER_AOA, ROLE_PAYMASTER_SUPER, ROLE_PERMISSION_LEVELS, RegistryABI, RegistryArtifact, ReputationSystemABI, ReputationSystemArtifact, RequirementChecker, RolePermissionLevel, SEPOLIA_CONTRACTS, SEPOLIA_V2_VERSIONS, SepoliaFaucetAPI, SessionKeyValidatorABI, SessionKeyValidatorArtifact, SimpleAccountABI, SimpleAccountArtifact, SimpleAccountFactoryABI, SimpleAccountFactoryArtifact, StateValidator, SuperPaymasterABI, SuperPaymasterArtifact, V2_SUMMARY, X402FacilitatorABI, X402FacilitatorArtifact, accountActions, accountFactoryActions, agentActions, agentRegistryActions, aggregatorActions, airAccountActions, airAccountFactoryActions, blsAlgorithmActions, channelActions, createAAStarPublicClient, createHeliosTransport, dvtActions, encodeDVTAccountSignature, encodeDVTVerifierProof, encodeG2Point, entryPointActions, forceExitActions, gTokenActions, gTokenAuthorizationActions, getAddressUrl, getAllCommunityConfigs, getAllV2Contracts, getBlockExplorer, getChainId, getCommunities, getCommunity, getCommunityConfig, getContract, getContractNetworks, getContracts, getCoreContracts, getDeploymentDate, getEntryPoint, getNetwork, getPaymasterV4_1, getRoleName, getRpcUrl, getSimpleAccountFactory, getSuperPaymasterV2, getTestAccounts, getTestTokenContracts, getTokenContracts, getTxUrl, getV2ContractByAddress, getV2ContractByName, getV2ContractsByDate, hashToFieldU0U1, isContractNetworkSupported, isRegisteredCommunity, isV2Contract, lookupAddress, paymasterActions, paymasterFactoryActions, policyRegistryActions, registryActions, reputationActions, resolveEns, resolveEnsVerified, sbtActions, sessionKeyValidatorActions, stakingActions, superPaymasterActions, tokenActions, x402Actions, x402IsNonceUsed, x402NonceKey, xPNTsFactoryABI, xPNTsFactoryActions, xPNTsFactoryArtifact, xPNTsTokenABI, xPNTsTokenActions, xPNTsTokenArtifact } from './chunk-ZSSNU3UF.js';
import { TEST_ACCOUNT_ADDRESSES, TOKEN_ADDRESSES, CORE_ADDRESSES, TEST_TOKEN_ADDRESSES } from './chunk-DSZ372PH.js';
export { AGENT_IDENTITY_REGISTRY_ADDRESS, AGENT_REPUTATION_REGISTRY_ADDRESS, ALL_ADDRESSES, APNTS_ADDRESS, BLS_AGGREGATOR_ADDRESS, BLS_VALIDATOR_ADDRESS, BPS_DENOMINATOR, CHAIN_MAINNET, CHAIN_SEPOLIA, COMMUNITY_OWNERS, CONTRACT_SRC_HASH, CORE_ADDRESSES, DEFAULT_APNTS_PRICE_USD, DEFAULT_CALL_GAS_LIMIT, DEFAULT_GAS_TOKEN_MINT_AMOUNT, DEFAULT_PRE_VERIFICATION_GAS, DEFAULT_TIMEOUT_MS, DEFAULT_TOKEN_NAME, DEFAULT_TOKEN_SYMBOL, DEFAULT_USDT_MINT_AMOUNT, DEFAULT_VERIFICATION_GAS_LIMIT, DVT_VALIDATOR_ADDRESS, ENTRY_POINT_ADDRESS, FAUCET_API_URL, GTOKEN_ADDRESS, GTOKEN_STAKING_ADDRESS, MAX_SERVICE_FEE, MICRO_PAYMENT_CHANNEL_ADDRESS, MONITORING_ADDRESSES, NODE_STAKE_AMOUNTS, OFFICIAL_ADDRESSES, PAYMASTER_ADDRESSES, PAYMASTER_FACTORY_ADDRESS, PAYMASTER_V4_ADDRESS, PAYMASTER_V4_IMPL_ADDRESS, REGISTRY_ADDRESS, REPUTATION_SYSTEM_ADDRESS, SBT_ADDRESS, SERVICE_FEE_RATE, SUPER_PAYMASTER_ADDRESS, TEST_ACCOUNT_ADDRESSES, TEST_ACCOUNT_POOL_SIZE, TEST_COMMUNITIES, TEST_TOKEN_ADDRESSES, TOKEN_ADDRESSES, XPNTS_FACTORY_ADDRESS, applyConfig } from './chunk-DSZ372PH.js';
import './chunk-PZ5AY32C.js';
import { keccak256, stringToBytes, createClient, publicActions, walletActions, parseAbi, decodeAbiParameters, encodeAbiParameters, zeroAddress, decodeErrorResult, formatEther, http, createPublicClient, createWalletClient, parseEther, erc20Abi, concat, pad, parseAbiParameters, toBytes, encodeFunctionData } from 'viem';
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
import * as fs from 'fs';

function createEndUserClient({
  chain,
  transport,
  account,
  addresses
}) {
  const client = createClient({
    chain,
    transport,
    account
  }).extend(publicActions).extend(walletActions);
  const usedAddresses = { ...CORE_ADDRESSES, ...TOKEN_ADDRESSES, ...TEST_ACCOUNT_ADDRESSES, ...addresses };
  console.log("   SDK Debug: simpleAccountFactory from usedAddresses:", usedAddresses.simpleAccountFactory);
  console.log("   SDK Debug: process.env.SIMPLE_ACCOUNT_FACTORY:", process.env.SIMPLE_ACCOUNT_FACTORY);
  const actions = {
    ...registryActions(usedAddresses.registry)(client),
    ...sbtActions(usedAddresses.mySBT)(client),
    ...superPaymasterActions(usedAddresses.superPaymaster)(client),
    ...paymasterActions(usedAddresses.paymasterV4)(client)
  };
  return Object.assign(client, actions, {
    async onboard({ community, roleId, roleData }) {
      console.log("\u{1F464} Onboarding user to community...");
      const result = await this.joinAndActivate({ community, roleId, roleData });
      console.log(`\u2705 User onboarded! SBT ID: ${result.sbtId}`);
      return { tx: result.tx, sbtId: result.sbtId };
    },
    async joinAndActivate({ community, roleId, roleData }) {
      const accountToUse = account;
      if (!accountToUse) throw new Error("Account required for joinAndActivate");
      console.log(`   SDK: Joining community ${community}...`);
      let finalData;
      if (roleData) {
        finalData = roleData;
      } else {
        const { encodeAbiParameters: encodeAbiParameters3 } = await import('viem');
        finalData = encodeAbiParameters3(
          [
            { name: "account", type: "address" },
            { name: "community", type: "address" },
            { name: "avatarURI", type: "string" },
            { name: "ensName", type: "string" },
            { name: "stakeAmount", type: "uint256" }
          ],
          [accountToUse.address, community, "", "", 0n]
          // Use minimum stake (Registry will use roleConfig.minStake)
        );
      }
      const regTx = await client.writeContract({
        address: usedAddresses.registry,
        abi: RegistryABI,
        functionName: "registerRoleSelf",
        args: [roleId, finalData],
        account: accountToUse,
        chain
      });
      await client.waitForTransactionReceipt({ hash: regTx });
      const sbtId = await actions.getUserSBT({ user: accountToUse.address });
      console.log(`   SDK: User joined. SBT ID: ${sbtId}`);
      let credit = 0n;
      try {
        const factoryAbi = parseAbi(["function communityToToken(address) view returns (address)"]);
        const tokenAddress = await client.readContract({
          address: usedAddresses.xPNTsFactory,
          abi: factoryAbi,
          functionName: "communityToToken",
          args: [community]
        });
        credit = await actions.getAvailableCredit({
          user: client.aaAddress || accountToUse.address,
          token: tokenAddress
        });
        console.log(`   SDK: Activation complete. Current Credit: ${credit} points.`);
      } catch (error) {
        console.log(`   SDK: Credit system not available (${error.message.split("\n")[0]}). Continuing...`);
      }
      return {
        tx: regTx,
        sbtId,
        initialCredit: credit
      };
    },
    async executeGasless({ target, data, value = 0n, operator }) {
      const accountToUse = account;
      if (!accountToUse) throw new Error("Wallet account required for gasless execution");
      const { accountAddress } = await this.createSmartAccount({ owner: accountToUse.address });
      console.log(`   SDK: Executing gasless via AA ${accountAddress} Sponsored by ${operator}`);
      let nonce = 0n;
      try {
        nonce = await client.readContract({
          address: usedAddresses.entryPoint,
          abi: [{
            type: "function",
            name: "getNonce",
            inputs: [{ type: "address", name: "sender" }, { type: "uint192", name: "key" }],
            outputs: [{ type: "uint256" }],
            stateMutability: "view"
          }],
          functionName: "getNonce",
          args: [accountAddress, 0n]
          // 0 = default nonce key
        });
      } catch (e) {
        console.warn(`   \u26A0\uFE0F  Failed to fetch nonce from EntryPoint, using default 0:`, e.message);
        nonce = 0n;
      }
      const { encodeFunctionData: encodeFunctionData2, concat: concat2, pad: pad2, keccak256: keccak2565 } = await import('viem');
      const executeData = encodeFunctionData2({
        abi: [{ type: "function", name: "execute", inputs: [{ type: "address" }, { type: "uint256" }, { type: "bytes" }] }],
        functionName: "execute",
        args: [target, value, data]
      });
      const accountGasLimits = concat2([
        pad2(`0x${1e5.toString(16)}`, { dir: "left", size: 16 }),
        // verification
        pad2(`0x${1e5.toString(16)}`, { dir: "left", size: 16 })
        // call
      ]);
      const gasFees = concat2([
        pad2(`0x${2e9.toString(16)}`, { dir: "left", size: 16 }),
        // 2 gwei
        pad2(`0x${2e9.toString(16)}`, { dir: "left", size: 16 })
        // 2 gwei
      ]);
      const paymasterVerificationGas = 250000n;
      const paymasterPostOpGas = 50000n;
      const paymasterAndData = concat2([
        usedAddresses.superPaymaster,
        pad2(`0x${paymasterVerificationGas.toString(16)}`, { dir: "left", size: 16 }),
        pad2(`0x${paymasterPostOpGas.toString(16)}`, { dir: "left", size: 16 }),
        operator
      ]);
      const userOp = {
        sender: accountAddress,
        nonce,
        initCode: "0x",
        callData: executeData,
        accountGasLimits,
        preVerificationGas: 50000n,
        gasFees,
        paymasterAndData,
        signature: "0x"
      };
      const entryPointAddress = usedAddresses.entryPoint || "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
      const userOpHash = await client.readContract({
        address: entryPointAddress,
        abi: [{
          type: "function",
          name: "getUserOpHash",
          inputs: [{
            type: "tuple",
            components: [
              { name: "sender", type: "address" },
              { name: "nonce", type: "uint256" },
              { name: "initCode", type: "bytes" },
              { name: "callData", type: "bytes" },
              { name: "accountGasLimits", type: "bytes32" },
              { name: "preVerificationGas", type: "uint256" },
              { name: "gasFees", type: "bytes32" },
              { name: "paymasterAndData", type: "bytes" },
              { name: "signature", type: "bytes" }
            ]
          }],
          outputs: [{ type: "bytes32" }],
          stateMutability: "view"
        }],
        functionName: "getUserOpHash",
        args: [userOp]
      });
      const signature = await accountToUse.signMessage({
        message: { raw: userOpHash }
      });
      userOp.signature = signature;
      console.log(`   SDK: Submitting UserOp ${userOpHash}...`);
      const tx = await client.writeContract({
        address: entryPointAddress,
        abi: [{
          type: "function",
          name: "handleOps",
          inputs: [
            {
              type: "tuple[]",
              components: [
                { name: "sender", type: "address" },
                { name: "nonce", type: "uint256" },
                { name: "initCode", type: "bytes" },
                { name: "callData", type: "bytes" },
                { name: "accountGasLimits", type: "bytes32" },
                { name: "preVerificationGas", type: "uint256" },
                { name: "gasFees", type: "bytes32" },
                { name: "paymasterAndData", type: "bytes" },
                { name: "signature", type: "bytes" }
              ]
            },
            { name: "beneficiary", type: "address" }
          ],
          outputs: [],
          stateMutability: "nonpayable"
        }],
        functionName: "handleOps",
        args: [[userOp], accountToUse.address],
        account,
        chain
      });
      await client.waitForTransactionReceipt({ hash: tx });
      return tx;
    },
    async checkJoinRequirements(address) {
      const accountToUse = address || account?.address;
      if (!accountToUse) throw new Error("Account address required for requirement check");
      const { RequirementChecker: RequirementChecker2 } = await import('./index.node-55LOPHNQ.js');
      const checker = new RequirementChecker2(client, usedAddresses);
      return await checker.checkRequirements({
        address: accountToUse,
        requiredGToken: 440000000000000000n,
        // 0.44 GT (stake + burn)
        requireSBT: false
      });
    },
    async createSmartAccount({ owner, salt = 0n }) {
      const { SimpleAccountFactoryABI: SimpleAccountFactoryABI2 } = await import('./index.node-55LOPHNQ.js');
      const { encodeFunctionData: encodeFunctionData2, concat: concat2 } = await import('viem');
      let factoryAddress = usedAddresses.simpleAccountFactory;
      console.log(`   SDK: Using SimpleAccountFactory: ${factoryAddress} (Owner: ${owner}, Salt: ${salt})`);
      if (!factoryAddress || factoryAddress === "0x0000000000000000000000000000000000000000") {
        console.warn("   \u26A0\uFE0F  SimpleAccountFactory not found in configuration. Using default fallback.");
        factoryAddress = "0x9406Cc6185a346906296840746125a0E44976454";
      }
      const accountAddress = await client.readContract({
        address: factoryAddress,
        abi: SimpleAccountFactoryABI2,
        functionName: "getAddress",
        args: [owner, salt]
      });
      const createAccountData = encodeFunctionData2({
        abi: SimpleAccountFactoryABI2,
        functionName: "createAccount",
        args: [owner, salt]
      });
      const initCode = concat2([factoryAddress, createAccountData]);
      const byteCode = await client.getBytecode({ address: accountAddress });
      const isDeployed = byteCode !== void 0 && byteCode !== "0x";
      return { accountAddress, initCode, isDeployed };
    },
    async deploySmartAccount({ owner, salt = 0n, fundWithETH = 0n }) {
      const { accountAddress, isDeployed } = await this.createSmartAccount({ owner, salt });
      const { formatEther: formatEther2 } = await import('viem');
      let deployHash = "0x0";
      if (isDeployed) {
        console.log(`   \u2139\uFE0F Account ${accountAddress} already deployed.`);
      } else {
        const { SimpleAccountFactoryABI: SimpleAccountFactoryABI2 } = await import('./index.node-55LOPHNQ.js');
        let factoryAddress = usedAddresses.simpleAccountFactory;
        if (!factoryAddress || factoryAddress === "0x0000000000000000000000000000000000000000") {
          factoryAddress = "0x9406Cc6185a346906296840746125a0E44976454";
        }
        console.log(`   \u{1F3ED} Deploying Smart Account for ${owner}...`);
        deployHash = await client.writeContract({
          address: factoryAddress,
          abi: SimpleAccountFactoryABI2,
          functionName: "createAccount",
          args: [owner, salt],
          account,
          chain
        });
        await client.waitForTransactionReceipt({ hash: deployHash });
        console.log(`   \u2705 Deployed at ${accountAddress}`);
      }
      if (fundWithETH > 0n) {
        console.log(`   \u26FD Funding account with ${formatEther2(fundWithETH)} ETH...`);
        const tx = await client.sendTransaction({
          to: accountAddress,
          value: fundWithETH,
          account,
          chain
        });
        await client.waitForTransactionReceipt({ hash: tx });
      }
      return { accountAddress, deployTxHash: deployHash, isDeployed: true };
    }
  });
}
var RoleIds = {
  PAYMASTER_SUPER: keccak256(stringToBytes("PAYMASTER_SUPER")),
  DVT: keccak256(stringToBytes("DVT")),
  // Replaced PAYMASTER
  PAYMASTER_AOA: keccak256(stringToBytes("PAYMASTER_AOA")),
  KMS: keccak256(stringToBytes("KMS")),
  COMMUNITY: keccak256(stringToBytes("COMMUNITY")),
  ENDUSER: keccak256(stringToBytes("ENDUSER")),
  ANODE: keccak256(stringToBytes("ANODE"))
};
var RoleDataFactory = {
  /**
   * Data for SuperPaymaster Operator (Empty)
   */
  paymasterSuper: () => "0x",
  /**
   * Data for Generic DVT Role (Empty)
   */
  dvt: () => "0x",
  /**
   * Data for Community Registration (matches Registry.sol CommunityRoleData)
   * NOTE: Solidity's abi.encode(struct) adds a 32-byte offset prefix (0x20)
   * which is required for abi.decode(struct) to work correctly.
   * 
   * @param params.name Community Name (defaults to 'TestCommunity')
   * @param params.ensName ENS name (optional)
   * @param params.website Website URL (optional)
   * @param params.description Community description (optional)
   * @param params.logoURI Logo URI string (optional)
   * @param params.stakeAmount Stake amount (defaults to 0)
   */
  community: (params) => {
    return encodeAbiParameters(
      [{
        type: "tuple",
        components: [
          { name: "name", type: "string" },
          { name: "ensName", type: "string" },
          { name: "website", type: "string" },
          { name: "description", type: "string" },
          { name: "logoURI", type: "string" },
          { name: "stakeAmount", type: "uint256" }
        ]
      }],
      [[
        params?.name || "TestCommunity",
        params?.ensName || "",
        params?.website || "",
        params?.description || "",
        params?.logoURI || "",
        params?.stakeAmount || 0n
      ]]
    );
  },
  /**
   * Data for EndUser (matches Registry.sol EndUserRoleData)
   */
  endUser: (params) => {
    return encodeAbiParameters(
      [{
        type: "tuple",
        components: [
          { name: "account", type: "address" },
          { name: "community", type: "address" },
          { name: "avatarURI", type: "string" },
          { name: "ensName", type: "string" },
          { name: "stakeAmount", type: "uint256" }
        ]
      }],
      [[
        params?.account || zeroAddress,
        params?.community || zeroAddress,
        params?.avatarURI || "",
        params?.ensName || "",
        params?.stakeAmount || 0n
      ]]
    );
  },
  decodeCommunity: (data) => {
    const decoded = decodeAbiParameters(
      [{
        type: "tuple",
        components: [
          { name: "name", type: "string" },
          { name: "ensName", type: "string" },
          { name: "website", type: "string" },
          { name: "description", type: "string" },
          { name: "logoURI", type: "string" },
          { name: "stakeAmount", type: "uint256" }
        ]
      }],
      data
    );
    const result = decoded[0];
    if (Array.isArray(result)) {
      const [n, e, w, d, l, s] = result;
      return { name: n, ensName: e, website: w, description: d, logoURI: l, stakeAmount: s };
    } else {
      return {
        name: result.name,
        ensName: result.ensName,
        website: result.website,
        description: result.description,
        logoURI: result.logoURI,
        stakeAmount: result.stakeAmount
      };
    }
  },
  decodeEndUser: (data) => {
    const decoded = decodeAbiParameters(
      [{
        type: "tuple",
        components: [
          { name: "account", type: "address" },
          { name: "community", type: "address" },
          { name: "avatarURI", type: "string" },
          { name: "ensName", type: "string" },
          { name: "stakeAmount", type: "uint256" }
        ]
      }],
      data
    );
    const result = decoded[0];
    if (Array.isArray(result)) {
      const [a, c, av, en, s] = result;
      return { account: a, community: c, avatarURI: av, ensName: en, stakeAmount: s };
    } else {
      return {
        account: result.account,
        community: result.community,
        avatarURI: result.avatarURI,
        ensName: result.ensName,
        stakeAmount: result.stakeAmount
      };
    }
  }
};
var CustomErrors = {
  RoleNotConfigured: "RoleNotConfigured(bytes32,bool)",
  RoleAlreadyGranted: "RoleAlreadyGranted(bytes32,address)",
  InsufficientStake: "InsufficientStake(uint256,uint256)"
};
function decodeContractError(error) {
  if (!error || typeof error !== "object") return null;
  if (error.name === "ContractFunctionExecutionError" || error.walk) {
    const internalError = error.walk ? error.walk((e) => e.data) : error;
    const data = internalError?.data;
    if (data) {
      try {
        const decoded = decodeErrorResult({
          abi: RegistryABI,
          data
        });
        if (decoded.errorName === "RoleNotConfigured") {
          const [roleId, isActive] = decoded.args;
          return `RoleNotConfigured: Role ${roleId} is ${isActive ? "ACTIVE" : "INACTIVE"} in Registry.`;
        }
        if (decoded.errorName === "RoleAlreadyGranted") {
          const [roleId, user] = decoded.args;
          return `RoleAlreadyGranted: User ${user} already has role ${roleId}.`;
        }
        if (decoded.errorName === "InsufficientStake") {
          const [stake, minStake] = decoded.args;
          return `InsufficientStake: Provided ${stake}, Required ${minStake}.`;
        }
        return `${decoded.errorName}: ${decoded.args}`;
      } catch (e) {
        return null;
      }
    }
  }
  return null;
}

// src/clients/operator.ts
function createOperatorClient({
  chain,
  transport,
  account,
  addresses
}) {
  const client = createClient({
    chain,
    transport,
    account
  }).extend(publicActions).extend(walletActions);
  const usedAddresses = { ...CORE_ADDRESSES, ...TEST_TOKEN_ADDRESSES, ...TEST_ACCOUNT_ADDRESSES, ...addresses };
  const spActions = superPaymasterActions(usedAddresses.superPaymaster)(client);
  const regActions = registryActions(usedAddresses.registry)(client);
  const stkActions = stakingActions(usedAddresses.gTokenStaking)(client);
  const pmV4Actions = paymasterActions(usedAddresses.paymasterV4)(client);
  const actions = {
    ...stkActions,
    ...spActions,
    ...pmV4Actions,
    ...regActions,
    async setup(args) {
      console.log("\u2699\uFE0F Setting up operator...");
      const txs = await this._onboardOperator(args);
      console.log(`\u2705 Operator setup complete! Transactions: ${txs.length}`);
      return { txs };
    },
    async onboardOperator(args) {
      return this.onboardFully(args);
    },
    async onboardFully(args) {
      return this._onboardOperator(args);
    },
    async deployPaymasterV4({ version = "v4.1", initData = "0x" } = {}) {
      console.log(`   SDK: Deploying Paymaster V4 (${version})...`);
      const tx = await client.writeContract({
        address: usedAddresses.paymasterFactory,
        abi: PaymasterFactoryABI,
        functionName: "deployPaymaster",
        args: [version, initData],
        account,
        chain
      });
      await client.waitForTransactionReceipt({ hash: tx });
      return tx;
    },
    async _onboardOperator({ stakeAmount, depositAmount, roleId, roleData }) {
      const txs = [];
      const accountToUse = account;
      if (!accountToUse) throw new Error("Account required for onboarding");
      try {
        console.log("   SDK: Fetching role config for entry burn...");
        const roleConfig = await client.readContract({
          address: usedAddresses.registry,
          abi: RegistryABI,
          functionName: "roleConfigs",
          args: [roleId]
        });
        const entryBurn = roleConfig[1];
        const totalStakeNeeded = stakeAmount + entryBurn;
        console.log(`   SDK: Approving GToken (Stake: ${stakeAmount}, Burn: ${entryBurn})...`);
        const approveGToken = await client.writeContract({
          address: usedAddresses.gToken,
          abi: erc20Abi,
          functionName: "approve",
          args: [usedAddresses.gTokenStaking, totalStakeNeeded],
          account: accountToUse,
          chain
        });
        await client.waitForTransactionReceipt({ hash: approveGToken });
        txs.push(approveGToken);
        let data;
        if (roleData && roleData !== "0x") {
          data = roleData;
        } else {
          console.log(`   SDK: Auto-generating roleData for roleId ${roleId}...`);
          if (roleId === keccak256(stringToBytes("COMMUNITY"))) {
            data = RoleDataFactory.community();
          } else if (roleId === keccak256(stringToBytes("ENDUSER"))) {
            data = RoleDataFactory.endUser();
          } else if (roleId === keccak256(stringToBytes("PAYMASTER_SUPER"))) {
            data = RoleDataFactory.paymasterSuper();
          } else {
            data = RoleDataFactory.paymasterSuper();
          }
        }
        console.log(`   SDK: Checking if role already granted...`);
        const hasRoleResult = await client.readContract({
          address: usedAddresses.registry,
          abi: RegistryABI,
          functionName: "hasRole",
          args: [roleId, accountToUse.address]
        });
        if (hasRoleResult) {
          console.log(`   \u2139\uFE0F  Role already granted, skipping registration`);
        } else {
          console.log(`   SDK: Registering role ${roleId}...`);
          const registerTx = await actions.registerRoleSelf({
            roleId,
            data,
            account: accountToUse
          });
          await client.waitForTransactionReceipt({ hash: registerTx });
          txs.push(registerTx);
        }
        if (depositAmount > 0n) {
          console.log("   SDK: Depositing aPNTs via depositFor...");
          const depositTx = await client.writeContract({
            address: usedAddresses.superPaymaster,
            abi: SuperPaymasterABI,
            functionName: "depositFor",
            args: [accountToUse.address, depositAmount],
            account: accountToUse,
            chain
          });
          await client.waitForTransactionReceipt({ hash: depositTx });
          txs.push(depositTx);
        }
        return txs;
      } catch (error) {
        const decodedMsg = decodeContractError(error);
        throw decodedMsg ? new Error(`Onboarding Failed: ${decodedMsg}`) : error;
      }
    },
    async onboardToSuperPaymaster(args) {
      return this.onboardOperator(args);
    },
    async configureOperator({ xPNTsToken, treasury, account: accountOverride }) {
      const tx = await spActions.configureOperator({
        xPNTsToken,
        opTreasury: treasury,
        account: accountOverride || account
      });
      await client.waitForTransactionReceipt({ hash: tx });
      return tx;
    },
    async getOperatorStatus(accountAddress) {
      try {
        const hasRole = await client.readContract({
          address: usedAddresses.registry,
          abi: RegistryABI,
          functionName: "hasRole",
          args: [keccak256(stringToBytes("PAYMASTER_SUPER")), accountAddress]
        });
        let operatorType = null;
        let superPaymasterInfo = null;
        let paymasterV4Info = null;
        if (hasRole && usedAddresses.superPaymaster) {
          const operatorData = await client.readContract({
            address: usedAddresses.superPaymaster,
            abi: SuperPaymasterABI,
            functionName: "operators",
            args: [accountAddress]
          });
          if (operatorData && operatorData[1]) {
            operatorType = "super";
            const xPNTsTokenAddr = operatorData[3];
            let exchangeRate = 0n;
            if (xPNTsTokenAddr && xPNTsTokenAddr !== zeroAddress) {
              try {
                exchangeRate = await client.readContract({
                  address: xPNTsTokenAddr,
                  abi: xPNTsTokenABI,
                  functionName: "exchangeRate"
                });
              } catch (rateErr) {
                const msg = rateErr instanceof Error ? rateErr.message : String(rateErr);
                if (!msg.includes("ContractFunctionExecutionError") && !msg.includes("code: -32")) {
                  console.warn(`   \u26A0\uFE0F Unexpected error reading exchangeRate from ${xPNTsTokenAddr}:`, msg);
                }
              }
            }
            superPaymasterInfo = {
              hasRole: true,
              isConfigured: true,
              balance: operatorData[0],
              exchangeRate,
              treasury: operatorData[6]
            };
          }
        }
        if (usedAddresses.paymasterFactory && usedAddresses.paymasterFactory !== zeroAddress) {
          try {
            const pmAddr = await client.readContract({
              address: usedAddresses.paymasterFactory,
              abi: PaymasterFactoryABI,
              functionName: "getPaymasterByOperator",
              args: [accountAddress]
            });
            if (pmAddr !== zeroAddress) {
              operatorType = operatorType || "v4";
              paymasterV4Info = {
                address: pmAddr,
                balance: await client.getBalance({ address: pmAddr })
              };
            }
          } catch (e) {
            console.warn(`   \u26A0\uFE0F Failed to fetch V4 info from factory ${usedAddresses.paymasterFactory}:`, e);
          }
        }
        return { type: operatorType, superPaymaster: superPaymasterInfo, paymasterV4: paymasterV4Info };
      } catch (error) {
        console.error("Error in getOperatorStatus:", error);
        return { type: null, superPaymaster: null, paymasterV4: null };
      }
    }
  };
  return Object.assign(client, actions);
}
function createCommunityClient({
  chain,
  transport,
  account,
  addresses
}) {
  const client = createClient({
    chain,
    transport,
    account
  }).extend(publicActions).extend(walletActions);
  const usedAddresses = { ...CORE_ADDRESSES, ...TEST_TOKEN_ADDRESSES, ...addresses };
  const registryActionsObj = registryActions(usedAddresses.registry)(client);
  const sbtActionsObj = sbtActions(usedAddresses.mySBT)(client);
  const launch = async (args) => {
    try {
      console.log(`\u{1F680} Launching community: ${args.name}`);
      if (!account) {
        throw new Error("Account is required for launch()");
      }
      const uniqueName = `${args.name}_${Date.now()}`;
      console.log(`   \u{1F4DD} Unique name: ${uniqueName}`);
      const roleData = RoleDataFactory.community({
        name: uniqueName,
        ensName: "",
        website: args.website || "",
        description: args.description || "",
        logoURI: args.logoURI || "",
        stakeAmount: 0n
      });
      console.log(`   \u2705 RoleData generated:`, roleData);
      console.log(`   \u{1F4CA} RoleData type:`, typeof roleData);
      console.log(`   \u{1F4CF} RoleData length:`, roleData?.length);
      const hasRole = await client.readContract({
        address: usedAddresses.registry,
        abi: RegistryABI,
        functionName: "hasRole",
        args: [RoleIds.COMMUNITY, account.address]
      });
      let registerTx;
      if (hasRole) {
        console.log(`   \u2139\uFE0F  Account already has COMMUNITY role. Skipping registration.`);
      } else {
        if (usedAddresses.gToken && usedAddresses.gTokenStaking) {
          console.log(`   \u{1F4B0} Checking GToken allowance...`);
          const balance = await client.readContract({
            address: usedAddresses.gToken,
            abi: erc20Abi,
            functionName: "balanceOf",
            args: [account.address]
          });
          if (balance < 50000000000000000000n) {
            console.warn(`   \u26A0\uFE0F Warning: Low GToken balance (${balance}). Registration may fail if minStake > balance.`);
          }
          const allowance = await client.readContract({
            address: usedAddresses.gToken,
            abi: erc20Abi,
            functionName: "allowance",
            args: [account.address, usedAddresses.gTokenStaking]
          });
          if (allowance < 50000000000000000000n) {
            console.log(`   \u{1F513} Approving GToken for Staking...`);
            const approveTx = await client.writeContract({
              address: usedAddresses.gToken,
              abi: erc20Abi,
              functionName: "approve",
              args: [usedAddresses.gTokenStaking, 115792089237316195423570985008687907853269984665640564039457584007913129639935n],
              // MaxUint256
              account
            });
            console.log(`   \u2705 Approved: ${approveTx}`);
            await client.waitForTransactionReceipt({ hash: approveTx });
          }
        }
        console.log(`   \u{1F4E4} Registering community role...`);
        try {
          registerTx = await registryActionsObj.registerRole({
            roleId: RoleIds.COMMUNITY,
            user: account.address,
            data: roleData,
            account
          });
          console.log(`   \u2705 Community registered: ${registerTx}`);
        } catch (e) {
          const isRoleError = e.message?.includes("RoleAlreadyGranted") || e.cause?.data?.errorName === "RoleAlreadyGranted" || e.name === "RoleAlreadyGranted" || e.name === "RoleAlreadyGranted";
          if (isRoleError) {
            console.log(`   \u2139\uFE0F  Role already granted (caught in tx). Skipping.`);
          } else {
            throw e;
          }
        }
      }
      let tokenAddress = "0x0000000000000000000000000000000000000000";
      const txs = [];
      if (registerTx) txs.push(registerTx);
      if (usedAddresses.xPNTsFactory) {
        if (!client.account) {
          throw new Error("Client account is required for token deployment");
        }
        const factoryAbi = [
          {
            type: "function",
            name: "deployxPNTsToken",
            inputs: [
              { name: "name", type: "string" },
              { name: "symbol", type: "string" },
              { name: "communityName", type: "string" },
              { name: "communityENS", type: "string" },
              { name: "exchangeRate", type: "uint256" },
              { name: "paymasterAOA", type: "address" }
            ],
            outputs: [{ name: "token", type: "address" }],
            stateMutability: "nonpayable"
          },
          {
            type: "function",
            name: "getTokenAddress",
            inputs: [{ name: "community", type: "address" }],
            outputs: [{ name: "token", type: "address" }],
            stateMutability: "view"
          }
        ];
        try {
          const existingToken = await client.readContract({
            address: usedAddresses.xPNTsFactory,
            abi: factoryAbi,
            functionName: "getTokenAddress",
            args: [account.address]
          });
          if (existingToken && existingToken !== "0x0000000000000000000000000000000000000000") {
            console.log(`   \u2139\uFE0F  Found existing token at ${existingToken}`);
            tokenAddress = existingToken;
            return { tokenAddress, txs };
          }
        } catch (e) {
          console.warn(`   \u26A0\uFE0F Failed to check for existing token:`, e);
        }
        console.log(`   \u{1F3ED} Deploying Token via Factory: ${usedAddresses.xPNTsFactory}`);
        try {
          const { request } = await client.simulateContract({
            address: usedAddresses.xPNTsFactory,
            abi: factoryAbi,
            functionName: "deployxPNTsToken",
            args: [
              args.tokenName,
              args.tokenSymbol,
              args.name,
              // communityName
              args.website || "",
              // communityENS (mapping website to ENS param for now)
              1000000000000000000n,
              // exchangeRate 1e18 (1:1)
              "0x0000000000000000000000000000000000000000"
              // paymasterAOA (optional)
            ],
            account: client.account
          });
          const deployTx = await client.writeContract(request);
          console.log(`   \u{1F4E4} Deploy Token Tx: ${deployTx}`);
          txs.push(deployTx);
          const receipt = await client.waitForTransactionReceipt({ hash: deployTx });
          const newTokenAddress = await client.readContract({
            address: usedAddresses.xPNTsFactory,
            abi: factoryAbi,
            functionName: "getTokenAddress",
            args: [account.address]
          });
          if (newTokenAddress) {
            tokenAddress = newTokenAddress;
            console.log(`   \u{1FA99} Token Deployed: ${tokenAddress}`);
          }
        } catch (deployError) {
          console.warn("   \u26A0\uFE0F Failed to deploy token, but community registered:", deployError);
        }
      }
      return { tokenAddress, txs };
    } catch (error) {
      console.error("\u274C Error in launch():", error);
      const errorMessage = error.message || "";
      const errorData = error.data?.errorName || "";
      const errorString = JSON.stringify(error);
      if (errorMessage.includes("RoleAlreadyGranted") || errorData === "RoleAlreadyGranted" || errorString.includes("RoleAlreadyGranted")) {
        throw new Error(`Account ${account?.address || "unknown"} already has COMMUNITY role. Please use a different account or exit the role first.`);
      }
      if (errorMessage.includes("InsufficientStake")) {
        throw new Error("Insufficient stake. Please ensure you have enough GToken staked.");
      }
      if (errorMessage.includes("RoleNotConfigured")) {
        throw new Error("COMMUNITY role is not configured in the Registry contract.");
      }
      throw error;
    }
  };
  const getCommunityInfo = async (accountAddress) => {
    try {
      const hasRole = await client.readContract({
        address: usedAddresses.registry,
        abi: RegistryABI,
        functionName: "hasRole",
        args: [RoleIds.COMMUNITY, accountAddress]
      });
      if (!hasRole) {
        return {
          hasRole: false,
          tokenAddress: null,
          communityData: null
        };
      }
      const factoryAbi = [
        {
          inputs: [{ name: "community", type: "address" }],
          name: "getTokenAddress",
          outputs: [{ name: "", type: "address" }],
          stateMutability: "view",
          type: "function"
        }
      ];
      const tokenAddress = await client.readContract({
        address: usedAddresses.xPNTsFactory,
        abi: factoryAbi,
        functionName: "getTokenAddress",
        args: [accountAddress]
      });
      const metadata = await client.readContract({
        address: usedAddresses.registry,
        abi: RegistryABI,
        functionName: "roleMetadata",
        args: [RoleIds.COMMUNITY, accountAddress]
      });
      let communityData = {
        name: "Community",
        ensName: "",
        website: "",
        description: "",
        logoURI: ""
      };
      if (metadata && metadata !== "0x") {
        try {
          const decoded = RoleDataFactory.decodeCommunity(metadata);
          communityData = {
            name: decoded.name || "Community",
            ensName: decoded.ensName || "",
            website: decoded.website || "",
            description: decoded.description || "",
            logoURI: decoded.logoURI || ""
          };
        } catch (e) {
          console.warn("   \u26A0\uFE0F Failed to decode community metadata:", e);
        }
      }
      return {
        hasRole: true,
        tokenAddress: tokenAddress && tokenAddress !== "0x0000000000000000000000000000000000000000" ? tokenAddress : null,
        communityData: metadata && metadata !== "0x" ? communityData : null
      };
    } catch (error) {
      console.error("Error fetching community info:", error);
      return {
        hasRole: false,
        tokenAddress: null,
        communityData: null
      };
    }
  };
  return Object.assign(client, registryActionsObj, sbtActionsObj, {
    launch,
    getCommunityInfo
  });
}
var ADDRESS_PLACEHOLDER = "0x0000000000000000000000000000000000000000";
function createAdminClient({
  chain,
  transport,
  account,
  addresses
}) {
  const baseClient = createClient({ chain, transport, account }).extend(publicActions).extend(walletActions);
  const usedAddresses = { ...CORE_ADDRESSES, ...TOKEN_ADDRESSES, ...addresses };
  const actions = {
    ...registryActions(usedAddresses.registry)(baseClient),
    ...superPaymasterActions(usedAddresses.superPaymaster)(baseClient),
    ...paymasterActions(usedAddresses.paymasterV4)(baseClient),
    ...stakingActions(usedAddresses.gTokenStaking)(baseClient),
    ...sbtActions(usedAddresses.mySBT)(baseClient),
    ...dvtActions(ADDRESS_PLACEHOLDER)(baseClient),
    ...xPNTsFactoryActions(usedAddresses.xPNTsFactory || "0x")(baseClient),
    ...aggregatorActions(ADDRESS_PLACEHOLDER)(baseClient)
  };
  return Object.assign(baseClient, actions);
}
var ExperimentClient = class {
  records = [];
  scenarioId;
  group;
  constructor(scenarioId, group) {
    this.scenarioId = scenarioId;
    this.group = group;
  }
  /**
   * Record a transaction result
   */
  recordTx(txHash, receipt, status, meta) {
    const gasUsed = BigInt(receipt.gasUsed || 0);
    const gasPrice = BigInt(receipt.effectiveGasPrice || 0);
    const costBN = gasUsed * gasPrice;
    const record = {
      id: `${Date.now()}-${Math.floor(Math.random() * 1e3)}`,
      scenario: this.scenarioId,
      group: this.group,
      txHash,
      gasUsed,
      gasPrice,
      costETH: formatEther(costBN),
      status,
      timestamp: Date.now(),
      meta
    };
    this.records.push(record);
    return record;
  }
  /**
   * Measure an async task (transaction) automatically
   */
  async measureTx(taskName, txPromise, publicClient) {
    console.log(`[Experiment: ${this.group}] Executing: ${taskName}...`);
    const start = Date.now();
    try {
      const hash = await txPromise;
      const receipt = await publicClient.waitForTransactionReceipt({ hash });
      this.recordTx(hash, receipt, "Success", { latency: Date.now() - start });
      const gasUsed = BigInt(receipt.gasUsed || 0);
      const gasPrice = BigInt(receipt.effectiveGasPrice || 0);
      console.log(`   \u2705 Success! Gas: ${gasUsed} | Cost: ${formatEther(gasUsed * gasPrice)} ETH`);
      return hash;
    } catch (e) {
      console.error(`   \u274C Failed: ${taskName}`, e);
      throw e;
    }
  }
  getRecords() {
    return this.records;
  }
};
var KeyManager = class {
  /**
   * 生成单个密钥对
   * @param name - 密钥名称（如 'Jason', 'Anni'）
   */
  static generateKeyPair(name) {
    const privateKey = generatePrivateKey();
    const account = privateKeyToAccount(privateKey);
    return {
      name,
      privateKey,
      address: account.address
    };
  }
  /**
   * 批量生成密钥对
   * @param names - 密钥名称数组
   */
  static generateKeyPairs(names) {
    return names.map((name) => this.generateKeyPair(name));
  }
  /**
   * 生成指定数量的密钥对（自动命名为 Operator_1, Operator_2, ...）
   * @param count - 数量
   * @param prefix - 名称前缀（默认 'Operator'）
   */
  static generateMultiple(count, prefix = "Operator") {
    const names = Array.from({ length: count }, (_, i) => `${prefix}_${i + 1}`);
    return this.generateKeyPairs(names);
  }
  /**
   * 保存密钥到 .env 文件
   * @param filePath - 文件路径（绝对路径）
   * @param keys - 密钥对数组
   * @param overwrite - 是否覆盖已存在的文件（默认 false）
   */
  static saveToEnvFile(filePath, keys, overwrite = false) {
    if (fs.existsSync(filePath) && !overwrite) {
      throw new Error(`File already exists: ${filePath}. Set overwrite=true to replace.`);
    }
    const content = keys.map(
      (k) => `${k.name.toUpperCase().replace(/\s+/g, "_")}_PRIVATE_KEY=${k.privateKey}`
    ).join("\n") + "\n";
    fs.writeFileSync(filePath, content, { mode: 384 });
    console.log(`\u2705 Keys saved to ${filePath} (${keys.length} keys)`);
  }
  /**
   * 从 .env 文件加载密钥
   * @param filePath - 文件路径（绝对路径）
   * @returns 密钥对数组
   */
  static loadFromEnvFile(filePath) {
    if (!fs.existsSync(filePath)) {
      throw new Error(`File not found: ${filePath}`);
    }
    const content = fs.readFileSync(filePath, "utf-8");
    const lines = content.split("\n").filter((line) => line.trim() && !line.startsWith("#"));
    return lines.map((line) => {
      const [key, value] = line.split("=");
      const name = key.replace(/_PRIVATE_KEY$/, "").toLowerCase().replace(/_/g, " ");
      const privateKey = value.trim();
      const account = privateKeyToAccount(privateKey);
      return {
        name,
        privateKey,
        address: account.address
      };
    });
  }
  /**
   * 保存密钥到 JSON 文件（包含地址信息）
   * @param filePath - 文件路径（绝对路径）
   * @param keys - 密钥对数组
   * @param overwrite - 是否覆盖已存在的文件（默认 false）
   */
  static saveToJsonFile(filePath, keys, overwrite = false) {
    if (fs.existsSync(filePath) && !overwrite) {
      throw new Error(`File already exists: ${filePath}. Set overwrite=true to replace.`);
    }
    const data = {
      generated: (/* @__PURE__ */ new Date()).toISOString(),
      keys: keys.map((k) => ({
        name: k.name,
        privateKey: k.privateKey,
        address: k.address
      }))
    };
    fs.writeFileSync(filePath, JSON.stringify(data, null, 2), { mode: 384 });
    console.log(`\u2705 Keys saved to ${filePath} (${keys.length} keys)`);
  }
  /**
   * 从 JSON 文件加载密钥
   * @param filePath - 文件路径（绝对路径）
   */
  static loadFromJsonFile(filePath) {
    if (!fs.existsSync(filePath)) {
      throw new Error(`File not found: ${filePath}`);
    }
    const content = fs.readFileSync(filePath, "utf-8");
    const data = JSON.parse(content);
    return data.keys.map((k) => ({
      name: k.name,
      privateKey: k.privateKey,
      address: k.address
    }));
  }
  /**
   * 打印密钥信息（隐藏私钥）
   * @param keys - 密钥对数组
   */
  static printKeys(keys, showPrivateKey = false) {
    console.log("\n\u{1F511} Generated Keys:");
    console.log("\u2500".repeat(80));
    keys.forEach((k, i) => {
      console.log(`${i + 1}. ${k.name}`);
      console.log(`   Address: ${k.address}`);
      if (showPrivateKey) {
        console.log(`   Private Key: ${k.privateKey}`);
      } else {
        console.log(`   Private Key: ${k.privateKey.slice(0, 10)}...${k.privateKey.slice(-8)}`);
      }
    });
    console.log("\u2500".repeat(80));
  }
};
var FundingManager = class {
  /**
   * 创建 PublicClient 和 WalletClient
   */
  static createClients(params) {
    const account = privateKeyToAccount(params.supplierKey);
    const transport = http(params.rpcUrl);
    const publicClient = createPublicClient({
      chain: params.chain,
      transport
    });
    const walletClient = createWalletClient({
      account,
      chain: params.chain,
      transport
    });
    return { publicClient, walletClient, account };
  }
  /**
   * 充值 ETH 到目标地址
   * @param params - 充值参数
   * @returns 充值结果
   */
  static async fundWithETH(params) {
    try {
      const { publicClient, walletClient } = this.createClients(params);
      const amount = parseEther(params.amount);
      console.log(`\u{1F4B8} Funding ${params.targetAddress} with ${params.amount} ETH...`);
      const hash = await walletClient.sendTransaction({
        account: walletClient.account,
        chain: params.chain,
        to: params.targetAddress,
        value: amount
      });
      console.log(`   Transaction Sent: ${hash}`);
      await publicClient.waitForTransactionReceipt({ hash });
      console.log(`   \u2705 ETH Funded.`);
      return { success: true, txHash: hash };
    } catch (error) {
      console.error(`   \u274C ETH Funding Failed:`, error);
      return { success: false, error: error.message };
    }
  }
  /**
   * 充值 ERC20 Token 到目标地址
   * @param params - 充值参数
   * @returns 充值结果
   */
  static async fundWithToken(params) {
    try {
      const { publicClient, walletClient, account } = this.createClients(params);
      const amount = parseEther(params.amount);
      console.log(`\u{1F4B8} Funding ${params.targetAddress} with ${params.amount} tokens...`);
      const { request } = await publicClient.simulateContract({
        account,
        address: params.tokenAddress,
        abi: erc20Abi,
        functionName: "transfer",
        args: [params.targetAddress, amount]
      });
      const hash = await walletClient.writeContract(request);
      console.log(`   Transaction Sent: ${hash}`);
      await publicClient.waitForTransactionReceipt({ hash });
      console.log(`   \u2705 Token Funded.`);
      return { success: true, txHash: hash };
    } catch (error) {
      console.error(`   \u274C Token Funding Failed:`, error);
      return { success: false, error: error.message };
    }
  }
  /**
   * 检查 ETH 余额
   * @param params - 基础参数
   * @returns ETH 余额（wei）
   */
  static async getETHBalance(params) {
    const { publicClient } = this.createClients(params);
    return await publicClient.getBalance({ address: params.targetAddress });
  }
  /**
   * 检查 ERC20 Token 余额
   * @param params - 基础参数
   * @param tokenAddress - Token 合约地址
   * @returns Token 余额
   */
  static async getTokenBalance(params, tokenAddress) {
    const { publicClient } = this.createClients(params);
    return await publicClient.readContract({
      address: tokenAddress,
      abi: erc20Abi,
      functionName: "balanceOf",
      args: [params.targetAddress]
    });
  }
  /**
   * 智能充值：检查余额，不足时自动充值
   * @param params - 充值参数
   * @returns 充值结果数组
   */
  static async ensureFunding(params) {
    const results = [];
    const { publicClient } = this.createClients(params);
    if (params.minETH && params.targetETH) {
      const ethBalance = await publicClient.getBalance({ address: params.targetAddress });
      const minETH = parseEther(params.minETH);
      parseEther(params.targetETH);
      if (ethBalance < minETH) {
        console.log(`\u26A0\uFE0F  ETH balance (${Number(ethBalance) / 1e18}) below threshold (${params.minETH})`);
        const result = await this.fundWithETH({
          ...params,
          amount: params.targetETH
        });
        results.push(result);
      } else {
        console.log(`\u2705 Sufficient ETH: ${Number(ethBalance) / 1e18} ETH`);
        results.push({ success: true });
      }
    }
    if (params.token) {
      const tokenBalance = await this.getTokenBalance(params, params.token.address);
      const minToken = params.token.minBalance ? parseEther(params.token.minBalance) : 0n;
      const targetToken = params.token.targetAmount ? parseEther(params.token.targetAmount) : 0n;
      if (tokenBalance < minToken && targetToken > 0n) {
        console.log(`\u26A0\uFE0F  Token balance (${Number(tokenBalance) / 1e18}) below threshold (${params.token.minBalance})`);
        const result = await this.fundWithToken({
          ...params,
          tokenAddress: params.token.address,
          amount: params.token.targetAmount
        });
        results.push(result);
      } else {
        console.log(`\u2705 Sufficient Token: ${Number(tokenBalance) / 1e18}`);
        results.push({ success: true });
      }
    }
    return results;
  }
  /**
   * 批量充值 ETH
   * @param params - 基础参数
   * @param targets - 目标地址和金额数组
   * @returns 充值结果数组
   */
  static async batchFundETH(params, targets) {
    const results = [];
    for (const target of targets) {
      const result = await this.fundWithETH({
        ...params,
        targetAddress: target.address,
        amount: target.amount
      });
      results.push(result);
    }
    return results;
  }
  /**
   * 批量充值 Token
   * @param params - 基础参数
   * @param tokenAddress - Token 合约地址
   * @param targets - 目标地址和金额数组
   * @returns 充值结果数组
   */
  static async batchFundToken(params, tokenAddress, targets) {
    const results = [];
    for (const target of targets) {
      const result = await this.fundWithToken({
        ...params,
        targetAddress: target.address,
        tokenAddress,
        amount: target.amount
      });
      results.push(result);
    }
    return results;
  }
};
var UserOperationBuilder = class {
  /**
   * Packs verificationGasLimit and callGasLimit into a bytes32 Hex string.
   */
  static packAccountGasLimits(verificationGasLimit, callGasLimit) {
    return concat([
      pad(`0x${verificationGasLimit.toString(16)}`, { dir: "left", size: 16 }),
      pad(`0x${callGasLimit.toString(16)}`, { dir: "left", size: 16 })
    ]);
  }
  /**
   * Packs maxPriorityFeePerGas and maxFeePerGas into a bytes32 Hex string.
   */
  static packGasFees(maxPriorityFeePerGas, maxFeePerGas) {
    return concat([
      pad(`0x${maxPriorityFeePerGas.toString(16)}`, { dir: "left", size: 16 }),
      pad(`0x${maxFeePerGas.toString(16)}`, { dir: "left", size: 16 })
    ]);
  }
  static estimatePreVerificationGasV07(userOp) {
    const nonce = typeof userOp.nonce === "bigint" ? userOp.nonce : typeof userOp.nonce === "number" ? BigInt(userOp.nonce) : BigInt(userOp.nonce);
    const preVerificationGas = typeof userOp.preVerificationGas === "bigint" ? userOp.preVerificationGas : typeof userOp.preVerificationGas === "number" ? BigInt(userOp.preVerificationGas) : BigInt(userOp.preVerificationGas);
    const encoded = encodeAbiParameters(
      parseAbiParameters("(address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)"),
      [
        [
          userOp.sender,
          nonce,
          userOp.initCode,
          userOp.callData,
          userOp.accountGasLimits,
          preVerificationGas,
          userOp.gasFees,
          userOp.paymasterAndData,
          userOp.signature
        ]
      ]
    );
    const bytes = toBytes(encoded);
    let calldataCost = 0n;
    for (const b of bytes) calldataCost += b === 0 ? 4n : 16n;
    return calldataCost + 26000n;
  }
  /**
   * Packs Paymaster parameters into the v0.7 paymasterAndData format.
   */
  static packPaymasterAndData(paymaster, paymasterGasLimit, paymasterPostOpGasLimit, paymasterData = "0x") {
    return concat([
      paymaster,
      pad(`0x${paymasterGasLimit.toString(16)}`, { dir: "left", size: 16 }),
      pad(`0x${paymasterPostOpGasLimit.toString(16)}`, { dir: "left", size: 16 }),
      paymasterData
    ]);
  }
  /**
   * Pack PaymasterV4 Deposit-Only paymasterAndData
   * 
   * v0.7 EntryPoint packs: [paymaster(20)][verificationGas(16)][postOpGas(16)][paymasterData]
   * Contract extracts token at offset 52 = paymasterData[0:20]
   * 
   * So paymasterData format must be: [token(20)][validUntil(6)][validAfter(6)]
   * 
   * @param paymaster - Paymaster address (20 bytes)
   * @param paymentToken - ERC20 token address (20 bytes, FIRST in paymasterData!)
   * @param validUntil - Validity end timestamp (6 bytes)
   * @param validAfter - Validity start timestamp (6 bytes)
   */
  static packPaymasterV4DepositData(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymentToken, validUntil, validAfter) {
    return concat([
      paymaster,
      pad(`0x${paymasterVerificationGasLimit.toString(16)}`, { dir: "left", size: 16 }),
      pad(`0x${paymasterPostOpGasLimit.toString(16)}`, { dir: "left", size: 16 }),
      paymentToken,
      pad(`0x${validUntil.toString(16)}`, { dir: "left", size: 6 }),
      pad(`0x${validAfter.toString(16)}`, { dir: "left", size: 6 })
    ]);
  }
  /**
   * Computes the UserOperation hash for signing.
   */
  static async getUserOpHash({
    userOp,
    entryPoint,
    chainId,
    publicClient
  }) {
    return await publicClient.readContract({
      address: entryPoint,
      abi: [{
        type: "function",
        name: "getUserOpHash",
        inputs: [{
          type: "tuple",
          components: [
            { name: "sender", type: "address" },
            { name: "nonce", type: "uint256" },
            { name: "initCode", type: "bytes" },
            { name: "callData", type: "bytes" },
            { name: "accountGasLimits", type: "bytes32" },
            { name: "preVerificationGas", type: "uint256" },
            { name: "gasFees", type: "bytes32" },
            { name: "paymasterAndData", type: "bytes" },
            { name: "signature", type: "bytes" }
          ]
        }],
        outputs: [{ type: "bytes32" }],
        stateMutability: "view"
      }],
      functionName: "getUserOpHash",
      args: [userOp]
    });
  }
  /**
   * Formats a PackedUserOperation into a JSON-RPC compatible object with hex-encoded strings.
   */
  static jsonifyUserOp(userOp) {
    const result = {
      sender: userOp.sender,
      nonce: userOp.nonce,
      initCode: userOp.initCode,
      callData: userOp.callData,
      accountGasLimits: userOp.accountGasLimits,
      preVerificationGas: userOp.preVerificationGas,
      gasFees: userOp.gasFees,
      paymasterAndData: userOp.paymasterAndData,
      signature: userOp.signature
    };
    const toCompactHex = (val) => {
      if (typeof val === "bigint") return `0x${val.toString(16)}`;
      if (typeof val === "number") return `0x${val.toString(16)}`;
      if (typeof val === "string") {
        if (val === "0x") return "0x0";
        if (val === "0x0") return "0x0";
        return val.replace(/^0x0+(?!$)/, "0x");
      }
      return val;
    };
    result.nonce = toCompactHex(result.nonce);
    result.preVerificationGas = toCompactHex(result.preVerificationGas);
    return result;
  }
  /**
   * Converts a PackedUserOperation to the Alchemy-specific v0.7 JSON format.
   * @param userOp - The packed UserOperation
   * @param options - Optional configuration
   * @param options.paymasterVerificationGasLimit - Gas limit for paymaster verification (default: 200000)
   * @param options.paymasterPostOpGasLimit - Gas limit for paymaster postOp (default: 200000)
   */
  static toAlchemyUserOperation(userOp, options) {
    const toHexStr = (val) => {
      if (val === void 0 || val === null) return void 0;
      if (typeof val === "bigint") return `0x${val.toString(16)}`;
      if (typeof val === "number") return `0x${val.toString(16)}`;
      if (typeof val === "string" && !val.startsWith("0x")) return `0x${val}`;
      return val;
    };
    const result = {
      sender: userOp.sender,
      nonce: toHexStr(userOp.nonce),
      callData: userOp.callData,
      signature: userOp.signature
    };
    if (userOp.accountGasLimits && userOp.accountGasLimits !== "0x") {
      const val = userOp.accountGasLimits.toString().startsWith("0x") ? userOp.accountGasLimits.slice(2) : userOp.accountGasLimits;
      const padded = val.padStart(64, "0");
      const verificationGasLimit = BigInt("0x" + padded.slice(0, 32));
      const callGasLimit = BigInt("0x" + padded.slice(32, 64));
      result.verificationGasLimit = `0x${verificationGasLimit.toString(16)}`;
      result.callGasLimit = `0x${callGasLimit.toString(16)}`;
    }
    if (userOp.gasFees && userOp.gasFees !== "0x") {
      const val = userOp.gasFees.toString().startsWith("0x") ? userOp.gasFees.slice(2) : userOp.gasFees;
      const padded = val.padStart(64, "0");
      const maxPriorityFeePerGas = BigInt("0x" + padded.slice(0, 32));
      const maxFeePerGas = BigInt("0x" + padded.slice(32, 64));
      result.maxPriorityFeePerGas = `0x${maxPriorityFeePerGas.toString(16)}`;
      result.maxFeePerGas = `0x${maxFeePerGas.toString(16)}`;
    }
    if (userOp.preVerificationGas) {
      result.preVerificationGas = `0x${BigInt(userOp.preVerificationGas).toString(16)}`;
    }
    if (userOp.initCode && userOp.initCode !== "0x") {
      const initCode = userOp.initCode.toString();
      result.factory = initCode.slice(0, 42);
      result.factoryData = "0x" + initCode.slice(42);
    }
    if (userOp.paymasterAndData && userOp.paymasterAndData !== "0x") {
      const pmd = userOp.paymasterAndData.toString().startsWith("0x") ? userOp.paymasterAndData.slice(2) : userOp.paymasterAndData;
      if (pmd.length >= 104) {
        result.paymaster = "0x" + pmd.slice(0, 40);
        const vGas = BigInt("0x" + pmd.slice(40, 72));
        const pGas = BigInt("0x" + pmd.slice(72, 104));
        result.paymasterVerificationGasLimit = `0x${vGas.toString(16)}`;
        result.paymasterPostOpGasLimit = `0x${pGas.toString(16)}`;
        result.paymasterData = "0x" + pmd.slice(104);
      } else if (pmd.length >= 40) {
        result.paymaster = "0x" + pmd.slice(0, 40);
        result.paymasterData = "0x" + pmd.slice(40);
        const defaultGasLimit = 200000n;
        result.paymasterVerificationGasLimit = `0x${(options?.paymasterVerificationGasLimit || defaultGasLimit).toString(16)}`;
        result.paymasterPostOpGasLimit = `0x${(options?.paymasterPostOpGasLimit || defaultGasLimit).toString(16)}`;
      }
    }
    return result;
  }
};
var UserOpScenarioType = /* @__PURE__ */ ((UserOpScenarioType2) => {
  UserOpScenarioType2["NATIVE"] = "NATIVE";
  UserOpScenarioType2["GASLESS_V4"] = "GASLESS_V4";
  UserOpScenarioType2["SUPER_BPNT"] = "SUPER_BPNT";
  UserOpScenarioType2["SUPER_CPNT"] = "SUPER_CPNT";
  UserOpScenarioType2["SUPER_CUSTOM"] = "SUPER_CUSTOM";
  return UserOpScenarioType2;
})(UserOpScenarioType || {});
var UserOpScenarioBuilder = class {
  /**
   * Builds a signed PackedUserOperation for a token transfer based on the specified scenario.
   */
  static async buildTransferScenario(type, params) {
    const {
      sender,
      ownerAccount,
      recipient,
      tokenAddress,
      amount,
      entryPoint,
      chainId,
      publicClient,
      paymaster,
      operator,
      paymasterGasLimit = 100000n,
      paymasterPostOpGasLimit = 40000n,
      nonceKey = 0n,
      gasToken
    } = params;
    const transferData = encodeFunctionData({
      abi: [{ name: "transfer", type: "function", inputs: [{ type: "address", name: "to" }, { type: "uint256", name: "amount" }], outputs: [{ type: "bool" }] }],
      functionName: "transfer",
      args: [recipient, amount]
    });
    const callData = encodeFunctionData({
      abi: [{ name: "execute", type: "function", inputs: [{ type: "address" }, { type: "uint256" }, { type: "bytes" }] }],
      functionName: "execute",
      args: [tokenAddress, 0n, transferData]
    });
    const userOp = {
      sender,
      nonce: await publicClient.readContract({
        address: entryPoint,
        abi: [{ name: "getNonce", type: "function", inputs: [{ type: "address" }, { type: "uint192" }], outputs: [{ type: "uint256" }] }],
        functionName: "getNonce",
        args: [sender, nonceKey]
      }),
      initCode: "0x",
      callData,
      accountGasLimits: UserOperationBuilder.packAccountGasLimits(type === "NATIVE" /* NATIVE */ ? 75000n : 250000n, 150000n),
      preVerificationGas: 80000n,
      gasFees: UserOperationBuilder.packGasFees(2000000000n, 2000000000n),
      // 2 Gwei
      paymasterAndData: "0x",
      signature: "0x"
    };
    if (type === "NATIVE" /* NATIVE */) {
      userOp.paymasterAndData = "0x";
    } else if (type === "GASLESS_V4" /* GASLESS_V4 */) {
      const pm = paymaster;
      const token = gasToken || tokenAddress;
      const validUntil = BigInt(Math.floor(Date.now() / 1e3) + 3600);
      const validAfter = BigInt(Math.floor(Date.now() / 1e3) - 100);
      if (!pm) throw new Error("paymaster address required for GASLESS_V4");
      if (!token) throw new Error("gasToken or tokenAddress required for GASLESS_V4");
      userOp.paymasterAndData = UserOperationBuilder.packPaymasterV4DepositData(
        pm,
        paymasterGasLimit,
        // paymasterVerificationGasLimit
        paymasterPostOpGasLimit,
        // paymasterPostOpGasLimit
        token,
        // Payment token
        validUntil,
        validAfter
      );
    } else if (type.startsWith("SUPER_")) {
      if (!paymaster || !operator) throw new Error("Paymaster and Operator required for SuperPM scenarios");
      userOp.paymasterAndData = UserOperationBuilder.packPaymasterAndData(
        paymaster,
        paymasterGasLimit,
        paymasterPostOpGasLimit,
        operator
      );
    }
    const opHash = await UserOperationBuilder.getUserOpHash({
      userOp,
      entryPoint,
      chainId,
      publicClient
    });
    const signature = await ownerAccount.signMessage({
      message: { raw: opHash }
    });
    userOp.signature = signature;
    const jsonUserOp = UserOperationBuilder.jsonifyUserOp(userOp);
    return { userOp: jsonUserOp, opHash };
  }
};

export { CustomErrors, ExperimentClient, FundingManager, KeyManager, RoleDataFactory, RoleIds, UserOpScenarioBuilder, UserOpScenarioType, UserOperationBuilder, createAdminClient, createCommunityClient, createEndUserClient, createOperatorClient, decodeContractError };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map