or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

contract-interaction.mdcore-deployment.mddeployment-management.mddiamond-deployment.mdindex.mdnamed-accounts.mdproxy-deployment.mdtest-fixtures.mdverification.md
tile.json

proxy-deployment.mddocs/

Proxy Deployment

Deploy and upgrade transparent proxies with automatic implementation detection, admin management, and support for various proxy patterns including OpenZeppelin and UUPS.

Capabilities

Proxy Deployment Options

Configure proxy deployment with implementation contracts, admin settings, and initialization.

interface ProxyOptions {
  /** Proxy admin owner address */
  owner?: Address;
  /** Number of upgrade iterations (for tracking) */
  upgradeIndex?: number;
  /** Custom proxy contract to use */
  proxyContract?: string | ArtifactData;
  /** Proxy constructor arguments template */
  proxyArgs?: any[];
  /** Proxy admin contract configuration */
  viaAdminContract?:
    | string
    | {
        name: string;
        artifact?: string | ArtifactData;
      };
  /** Custom name for implementation deployment */
  implementationName?: string;
  /** Check for ABI conflicts between proxy and implementation */
  checkABIConflict?: boolean;
  /** Check proxy admin ownership */
  checkProxyAdmin?: boolean;
  /** Simple initialization method name */
  methodName?: string;
  /** Initialization function configuration */
  execute?:
    | {
        methodName: string;
        args: any[];
      }
    | {
        init: {
          methodName: string;
          args: any[];
        };
        onUpgrade?: {
          methodName: string;
          args: any[];
        };
      };
  /** Upgrade function configuration */
  upgradeFunction?: {
    methodName: string;
    upgradeArgs: any[];
  };
}

Usage Examples:

import { deployments, getNamedAccounts } from "hardhat";

// Basic proxy deployment
const { deployer } = await getNamedAccounts();
await deployments.deploy("MyProxy", {
  from: deployer,
  proxy: {
    proxyContract: "OptimizedTransparentProxy",
    execute: {
      methodName: "initialize",
      args: ["param1", "param2"],
    },
  },
  args: ["constructor", "args"], // Implementation constructor args
});

// UUPS proxy deployment
await deployments.deploy("UUPSProxy", {
  from: deployer,
  proxy: {
    proxyContract: "UUPS",
    execute: {
      init: {
        methodName: "initialize",
        args: ["init", "params"],
      },
      onUpgrade: {
        methodName: "reinitialize",
        args: ["upgrade", "params"],
      },
    },
  },
});

// Custom proxy admin
await deployments.deploy("AdminProxy", {
  from: deployer,
  proxy: {
    proxyContract: "OpenZeppelinTransparentProxy",
    viaAdminContract: {
      name: "CustomProxyAdmin",
      artifact: "MyProxyAdmin",
    },
    owner: "0x1234567890123456789012345678901234567890",
  },
});

Proxy Types

Built-in support for multiple proxy patterns with automatic configuration.

// Built-in proxy contract options:
// - "EIP173Proxy" - Basic EIP-173 proxy
// - "EIP173ProxyWithReceive" - EIP-173 proxy with receive function
// - "OpenZeppelinTransparentProxy" - OpenZeppelin transparent proxy
// - "OptimizedTransparentProxy" - Gas-optimized transparent proxy
// - "UUPS" - Universal Upgradeable Proxy Standard

Usage Examples:

// EIP-173 proxy with receive function
await deployments.deploy("PayableProxy", {
  from: deployer,
  proxy: {
    proxyContract: "EIP173ProxyWithReceive",
    methodName: "initialize",
  },
  value: ethers.utils.parseEther("1.0"), // Send ETH to proxy
});

// OpenZeppelin transparent proxy with default admin
await deployments.deploy("OZProxy", {
  from: deployer,
  proxy: {
    proxyContract: "OpenZeppelinTransparentProxy",
    viaAdminContract: "DefaultProxyAdmin", // Uses built-in ProxyAdmin
  },
});

// Custom proxy contract
await deployments.deploy("CustomProxy", {
  from: deployer,
  proxy: {
    proxyContract: {
      abi: [...], // Custom proxy ABI
      bytecode: "0x...", // Custom proxy bytecode
    },
    proxyArgs: ["{implementation}", "{admin}", "{data}"],
  },
});

Upgrade Management

Automatic upgrade detection and execution based on implementation changes.

Usage Examples:

// Upgrade tracking with upgradeIndex
await deployments.deploy("VersionedProxy", {
  from: deployer,
  proxy: {
    upgradeIndex: 2, // Only upgrade if current version < 2
    execute: {
      onUpgrade: {
        methodName: "upgradeToV2",
        args: ["new", "features"],
      },
    },
  },
});

// Custom upgrade function
await deployments.deploy("CustomUpgradeProxy", {
  from: deployer,
  proxy: {
    upgradeFunction: {
      methodName: "customUpgrade",
      upgradeArgs: ["{proxy}", "{implementation}", "{data}"],
    },
  },
});

// Conditional initialization
await deployments.deploy("ConditionalProxy", {
  from: deployer,
  proxy: {
    execute: {
      init: {
        methodName: "initialize",
        args: ["initial", "setup"],
      },
      onUpgrade: {
        methodName: "migrate",
        args: ["migration", "data"],
      },
    },
  },
});

Implementation Management

Control implementation deployment and naming for better organization.

Usage Examples:

// Custom implementation name
await deployments.deploy("MyProxy", {
  from: deployer,
  proxy: {
    implementationName: "MyContract_V2_Implementation",
  },
  contract: "MyContractV2", // Different contract for implementation
});

// Skip ABI conflict checking for custom proxies
await deployments.deploy("FlexibleProxy", {
  from: deployer,
  proxy: {
    checkABIConflict: false,
    checkProxyAdmin: false,
    proxyContract: "CustomMinimalProxy",
  },
});

// Reuse existing implementation
await deployments.deploy("SharedImplementationProxy", {
  from: deployer,
  proxy: true,
  contract: "SharedContract", // Will reuse if already deployed
  skipIfAlreadyDeployed: true,
});

Types

interface ProxyOptionsBase {
  owner?: Address;
  upgradeIndex?: number;
  proxyContract?: string | ArtifactData;
  proxyArgs?: any[];
  viaAdminContract?:
    | string
    | {
        name: string;
        artifact?: string | ArtifactData;
      };
  implementationName?: string;
  checkABIConflict?: boolean;
  checkProxyAdmin?: boolean;
  upgradeFunction?: {
    methodName: string;
    upgradeArgs: any[];
  };
}

type ProxyOptions =
  | (ProxyOptionsBase & {
      methodName?: string;
    })
  | (ProxyOptionsBase & {
      execute?:
        | {
            methodName: string;
            args: any[];
          }
        | {
            init: {
              methodName: string;
              args: any[];
            };
            onUpgrade?: {
              methodName: string;
              args: any[];
            };
          };
    });

interface ArtifactData {
  abi: ABI;
  bytecode: string;
  deployedBytecode?: string;
  metadata?: string;
  methodIdentifiers?: any;
  storageLayout?: any;
  userdoc?: any;
  devdoc?: any;
  gasEstimates?: any;
}

type Address = string;
type ABI = any[];