or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

access-control.mdaccount-abstraction.mdfinance.mdgovernance.mdindex.mdmathematical-utilities.mdmeta-transactions.mdproxy-patterns.mdsecurity-utilities.mdtoken-standards.md

proxy-patterns.mddocs/

0

# Proxy Patterns

1

2

Comprehensive upgradeability patterns enabling contract logic updates while preserving state and addresses, including transparent proxies, UUPS, beacon patterns, and minimal clones.

3

4

## Capabilities

5

6

### ERC1967 Proxy Standard

7

8

Core proxy implementation using standardized storage slots to prevent storage collisions in upgradeable contracts.

9

10

```solidity { .api }

11

/**

12

* @dev Utilities for ERC1967 proxy pattern with standardized storage slots

13

*/

14

library ERC1967Utils {

15

/**

16

* @dev Returns the current implementation address from storage

17

*/

18

function getImplementation() internal view returns (address);

19

20

/**

21

* @dev Upgrades implementation and calls new contract with data

22

*/

23

function upgradeToAndCall(address newImplementation, bytes memory data) internal;

24

25

/**

26

* @dev Returns the current admin address from storage

27

*/

28

function getAdmin() internal view returns (address);

29

30

/**

31

* @dev Changes the admin of the proxy

32

*/

33

function changeAdmin(address newAdmin) internal;

34

35

/**

36

* @dev Returns the current beacon address from storage

37

*/

38

function getBeacon() internal view returns (address);

39

40

/**

41

* @dev Upgrades beacon and calls new implementation with data

42

*/

43

function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal;

44

}

45

46

/**

47

* @dev Basic ERC1967 proxy with upgradeable implementation storage

48

*/

49

contract ERC1967Proxy is Proxy {

50

/**

51

* @dev Initializes proxy with implementation and optional setup call

52

*/

53

constructor(address implementation, bytes memory _data);

54

55

/**

56

* @dev Returns current implementation address from ERC1967 storage slot

57

*/

58

function _implementation() internal view virtual override returns (address);

59

}

60

```

61

62

### Transparent Upgradeable Proxy

63

64

Admin-controlled upgrade pattern that prevents function selector clashing between proxy and implementation.

65

66

```solidity { .api }

67

/**

68

* @dev Transparent proxy with separate admin for upgrade control

69

*/

70

contract TransparentUpgradeableProxy is ERC1967Proxy {

71

/**

72

* @dev Initializes transparent proxy with logic, admin, and setup data

73

*/

74

constructor(address _logic, address initialOwner, bytes memory _data);

75

76

/**

77

* @dev Fallback implementing transparent pattern (admin vs user calls)

78

*/

79

fallback() external payable virtual override;

80

}

81

82

/**

83

* @dev Admin contract for managing transparent upgradeable proxies

84

*/

85

contract ProxyAdmin is Ownable {

86

/**

87

* @dev Current interface version for upgrade compatibility

88

*/

89

string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

90

91

/**

92

* @dev Upgrades proxy to new implementation with initialization call

93

*/

94

function upgradeAndCall(

95

ITransparentUpgradeableProxy proxy,

96

address implementation,

97

bytes memory data

98

) public payable virtual onlyOwner;

99

}

100

```

101

102

**Usage Example:**

103

104

```solidity

105

import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

106

import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

107

108

// Deploy implementation

109

MyContract implementation = new MyContract();

110

111

// Deploy proxy admin

112

ProxyAdmin admin = new ProxyAdmin(msg.sender);

113

114

// Deploy transparent proxy

115

bytes memory initData = abi.encodeCall(MyContract.initialize, (param1, param2));

116

TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(

117

address(implementation),

118

address(admin),

119

initData

120

);

121

122

// Later upgrade through admin

123

MyContractV2 newImplementation = new MyContractV2();

124

admin.upgradeAndCall(

125

ITransparentUpgradeableProxy(address(proxy)),

126

address(newImplementation),

127

""

128

);

129

```

130

131

### UUPS (Universal Upgradeable Proxy Standard)

132

133

Implementation-controlled upgrade pattern where the logic contract manages its own upgrades for gas efficiency.

134

135

```solidity { .api }

136

/**

137

* @dev UUPS upgradeable implementation with self-managed upgrades

138

*/

139

abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Utils {

140

/**

141

* @dev Upgrades implementation and calls new contract with data

142

*/

143

function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy;

144

145

/**

146

* @dev Returns ERC1822 compatible UUID for this implementation

147

*/

148

function proxiableUUID() external view virtual notDelegated returns (bytes32);

149

150

/**

151

* @dev Authorization function for upgrades (must be implemented by inheriting contract)

152

*/

153

function _authorizeUpgrade(address newImplementation) internal virtual;

154

155

/**

156

* @dev Modifier ensuring execution only through proxy delegatecall

157

*/

158

modifier onlyProxy();

159

160

/**

161

* @dev Modifier ensuring execution only in implementation context

162

*/

163

modifier notDelegated();

164

}

165

```

166

167

**Usage Example:**

168

169

```solidity

170

import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";

171

import "@openzeppelin/contracts/access/Ownable.sol";

172

173

contract MyUpgradeableContract is UUPSUpgradeable, OwnableUpgradeable {

174

function initialize(address owner) public initializer {

175

__Ownable_init(owner);

176

__UUPSUpgradeable_init();

177

}

178

179

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

180

}

181

182

// Deploy with ERC1967Proxy

183

MyUpgradeableContract implementation = new MyUpgradeableContract();

184

bytes memory initData = abi.encodeCall(MyUpgradeableContract.initialize, (owner));

185

ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), initData);

186

187

// Upgrade through the proxy

188

MyUpgradeableContract proxyAsContract = MyUpgradeableContract(address(proxy));

189

MyUpgradeableContractV2 newImplementation = new MyUpgradeableContractV2();

190

proxyAsContract.upgradeToAndCall(address(newImplementation), "");

191

```

192

193

### Beacon Proxy Pattern

194

195

Centralized upgrade mechanism where multiple proxies point to a single beacon for coordinated upgrades.

196

197

```solidity { .api }

198

/**

199

* @dev Beacon interface for implementation address resolution

200

*/

201

interface IBeacon {

202

/**

203

* @dev Returns the current implementation address

204

*/

205

function implementation() external view returns (address);

206

}

207

208

/**

209

* @dev Upgradeable beacon managing implementation for multiple proxies

210

*/

211

contract UpgradeableBeacon is IBeacon, Ownable {

212

/**

213

* @dev Returns current implementation address

214

*/

215

function implementation() public view virtual returns (address);

216

217

/**

218

* @dev Upgrades implementation for all connected beacon proxies

219

*/

220

function upgradeTo(address newImplementation) public virtual onlyOwner;

221

}

222

223

/**

224

* @dev Proxy that gets implementation address from a beacon

225

*/

226

contract BeaconProxy is Proxy {

227

/**

228

* @dev Initializes proxy with beacon and optional setup call

229

*/

230

constructor(address beacon, bytes memory data);

231

232

/**

233

* @dev Returns beacon address

234

*/

235

function _getBeacon() internal view virtual returns (address);

236

237

/**

238

* @dev Returns implementation from beacon

239

*/

240

function _implementation() internal view virtual override returns (address);

241

}

242

```

243

244

**Usage Example:**

245

246

```solidity

247

// Deploy implementation and beacon

248

MyContract implementation = new MyContract();

249

UpgradeableBeacon beacon = new UpgradeableBeacon(address(implementation), owner);

250

251

// Deploy multiple beacon proxies

252

bytes memory initData = abi.encodeCall(MyContract.initialize, (param));

253

BeaconProxy proxy1 = new BeaconProxy(address(beacon), initData);

254

BeaconProxy proxy2 = new BeaconProxy(address(beacon), initData);

255

256

// Upgrade all proxies at once through beacon

257

MyContractV2 newImplementation = new MyContractV2();

258

beacon.upgradeTo(address(newImplementation));

259

```

260

261

### Minimal Clones (EIP-1167)

262

263

Ultra-lightweight, non-upgradeable proxy pattern for cost-efficient contract deployment via clone factories.

264

265

```solidity { .api }

266

/**

267

* @dev Library for creating minimal proxy clones (EIP-1167)

268

*/

269

library Clones {

270

/**

271

* @dev Creates clone using CREATE opcode

272

*/

273

function clone(address implementation) internal returns (address instance);

274

275

/**

276

* @dev Creates clone using CREATE2 with deterministic address

277

*/

278

function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance);

279

280

/**

281

* @dev Creates clone with immutable arguments appended

282

*/

283

function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance);

284

285

/**

286

* @dev Predicts address for deterministic clone

287

*/

288

function predictDeterministicAddress(

289

address implementation,

290

bytes32 salt,

291

address deployer

292

) internal pure returns (address predicted);

293

294

/**

295

* @dev Retrieves immutable arguments from clone instance

296

*/

297

function fetchCloneArgs(address instance) internal pure returns (bytes memory args);

298

}

299

```

300

301

**Usage Example:**

302

303

```solidity

304

import "@openzeppelin/contracts/proxy/Clones.sol";

305

306

contract TokenFactory {

307

address public immutable implementation;

308

309

constructor() {

310

implementation = address(new MyToken());

311

}

312

313

function createToken(string memory name, string memory symbol) external returns (address) {

314

// Create minimal clone

315

address clone = Clones.clone(implementation);

316

317

// Initialize the clone

318

MyToken(clone).initialize(name, symbol, msg.sender);

319

320

return clone;

321

}

322

323

function createDeterministicToken(

324

string memory name,

325

string memory symbol,

326

bytes32 salt

327

) external returns (address) {

328

// Create deterministic clone

329

address clone = Clones.cloneDeterministic(implementation, salt);

330

MyToken(clone).initialize(name, symbol, msg.sender);

331

return clone;

332

}

333

}

334

```

335

336

### Proxy Initialization

337

338

Safe initialization patterns for proxy contracts preventing double-initialization and supporting versioned upgrades.

339

340

```solidity { .api }

341

/**

342

* @dev Initialization utility for proxy contracts with version support

343

*/

344

abstract contract Initializable {

345

/**

346

* @dev Disables initializers (use in implementation constructor)

347

*/

348

function _disableInitializers() internal virtual;

349

350

/**

351

* @dev Returns current initialized version

352

*/

353

function _getInitializedVersion() internal view returns (uint64);

354

355

/**

356

* @dev Returns true if currently in initialization phase

357

*/

358

function _isInitializing() internal view returns (bool);

359

360

/**

361

* @dev Modifier allowing single initialization (version 1)

362

*/

363

modifier initializer();

364

365

/**

366

* @dev Modifier allowing versioned re-initialization

367

*/

368

modifier reinitializer(uint64 version);

369

370

/**

371

* @dev Modifier restricting access to initialization phase only

372

*/

373

modifier onlyInitializing();

374

}

375

```

376

377

**Usage Example:**

378

379

```solidity

380

import "@openzeppelin/contracts/proxy/utils/Initializable.sol";

381

382

contract MyUpgradeableContract is Initializable {

383

string public name;

384

address public owner;

385

386

/// @custom:oz-upgrades-unsafe-allow constructor

387

constructor() {

388

_disableInitializers();

389

}

390

391

function initialize(string memory _name, address _owner) public initializer {

392

name = _name;

393

owner = _owner;

394

}

395

396

function initializeV2(string memory _name, address _owner, uint256 _newFeature) public reinitializer(2) {

397

name = _name;

398

owner = _owner;

399

// Initialize new features for V2

400

}

401

}

402

```

403

404

### Base Proxy Implementation

405

406

Abstract proxy contract providing core delegation functionality for all proxy patterns.

407

408

```solidity { .api }

409

/**

410

* @dev Abstract proxy contract with core delegation logic

411

*/

412

abstract contract Proxy {

413

/**

414

* @dev Returns implementation address (must be implemented by inheriting contracts)

415

*/

416

function _implementation() internal view virtual returns (address);

417

418

/**

419

* @dev Performs delegatecall to implementation

420

*/

421

function _delegate(address implementation) internal virtual;

422

423

/**

424

* @dev Internal fallback logic

425

*/

426

function _fallback() internal virtual;

427

428

/**

429

* @dev External fallback function

430

*/

431

fallback() external payable virtual;

432

433

/**

434

* @dev Receive function for ETH transfers

435

*/

436

receive() external payable virtual;

437

}

438

```

439

440

## Types

441

442

```solidity { .api }

443

/**

444

* @dev ERC-1967 standardized storage slots

445

*/

446

bytes32 constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

447

bytes32 constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

448

bytes32 constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

449

450

/**

451

* @dev ERC-1822 Universal Upgradeable Proxy Standard interface

452

*/

453

interface IERC1822Proxiable {

454

/**

455

* @dev Returns the storage slot used by the implementation

456

*/

457

function proxiableUUID() external view returns (bytes32);

458

}

459

460

/**

461

* @dev ERC-1967 Proxy Storage Slots interface

462

*/

463

interface IERC1967 {

464

event Upgraded(address indexed implementation);

465

event AdminChanged(address previousAdmin, address newAdmin);

466

event BeaconUpgraded(address indexed beacon);

467

}

468

469

/**

470

* @dev Transparent upgradeable proxy interface

471

*/

472

interface ITransparentUpgradeableProxy is IERC1967 {

473

function upgradeToAndCall(address newImplementation, bytes calldata data) external payable;

474

}

475

```