Skip to content

CCIP-9118: Add BurnMintERC20Transparent and TransparentUpgradeableProxy (including ProxyAdmin) from OpenZeppelin#20999

Merged
athegaul merged 14 commits intodevelopfrom
CCIP-9118/add-transparent-upgradable-proxy
Feb 4, 2026
Merged

CCIP-9118: Add BurnMintERC20Transparent and TransparentUpgradeableProxy (including ProxyAdmin) from OpenZeppelin#20999
athegaul merged 14 commits intodevelopfrom
CCIP-9118/add-transparent-upgradable-proxy

Conversation

@athegaul
Copy link
Contributor

@athegaul athegaul commented Feb 2, 2026

This PR implements the full deployment for the BurnMintERC20Transparent token using the standard OpenZeppelin Transparent Upgradeable Proxy (TUP) pattern.

Contracts

Transparent Proxy Pattern: Adopted OpenZeppelin v5 TransparentUpgradeableProxy:

  • Logic: BurnMintERC20Transparent (Implementation)
  • Admin: ProxyAdmin (automatically deployed to manage upgrades).

PR: smartcontractkit/ccip-contract-examples#10

CLD

The following changes will be added to durable pipeline, when calling changesets:

environment: <environment>
domain: ccip
changesets:
  - deploy_burn_mint_erc20_transparent_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              maxSupply: 0
              preMint: 0
  - deploy_transparent_upgradeable_proxy_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              burnMintERC20Transparent: "0xD3FA300206659889240EB21a62a9C1c95bB80959" # First we need to deploy BurnMintERC20Trasnaprent before we can run any of the operations
              symbol: TEST01302026
              decimals: 18
              maxSupply: 0
              preMint: 0
              initialize: true
  - save_proxy_admin_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              symbol: TEST01302026
  - transfer_proxy_admin_ownership_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              symbol: TEST01302026
              newOwner: "0xb14F1fEd84a0Cc0302B10ea6bFFBD87a970a5D32"
  - transparent_upgradeable_proxy_grant_role_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              - symbol: TEST01302026
                role: BURNER_ROLE
                account: "0xb14F1fEd84a0Cc0302B10ea6bFFBD87a970a5D32"
              - symbol: TEST01302026
                role: MINTER_ROLE
                account: "0xb14F1fEd84a0Cc0302B10ea6bFFBD87a970a5D32"
  - transparent_upgradeable_proxy_begin_default_admin_transfer_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              symbol: TEST01302026
              newAdmin: "0xb14F1fEd84a0Cc0302B10ea6bFFBD87a970a5D32"
  - transparent_upgradeable_proxy_accept_default_admin_transfer_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              symbol: TEST01302026
  - transparent_upgradeable_proxy_set_ccip_admin_evm:
      chainOverrides:
        - 10344971235874465080
      payload:
        tokens:
          10344971235874465080:
            TEST01302026:
              symbol: TEST01302026
              newAdmin: "0xb14F1fEd84a0Cc0302B10ea6bFFBD87a970a5D32"

@athegaul athegaul requested review from a team as code owners February 2, 2026 21:46
@product-security-plaid-production product-security-plaid-production bot requested review from gustavogama-cll and jmank88 and removed request for jmank88 February 2, 2026 21:47
@athegaul athegaul marked this pull request as draft February 2, 2026 21:47
@athegaul athegaul marked this pull request as ready for review February 2, 2026 22:00
@b-gopalswami b-gopalswami requested a review from a team as a code owner February 3, 2026 15:19
@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2026

CORA - Pending Reviewers

All codeowners have approved! ✅

Legend: ✅ Approved | ❌ Changes Requested | 💬 Commented | 🚫 Dismissed | ⏳ Pending | ❓ Unknown

For more details, see the full review summary.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2026

I see you updated files related to core. Please run pnpm changeset in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

@trunk-io
Copy link

trunk-io bot commented Feb 3, 2026

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

b-gopalswami
b-gopalswami previously approved these changes Feb 3, 2026

cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm"
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
"github.com/smartcontractkit/chainlink-evm/gethwrappers/shared/generated/1_5_0/burn_mint_erc20_transparent"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this have to be in 1.5? or was it already present in 1.5?
Just because the previous version gethwrappers are hard to generate :( would be great if we can move it to the latest versions

"github.com/smartcontractkit/chainlink/deployment/ccip/shared/stateview"
)

var _ cldf.ChangeSet[BurnMintERC20TransparentChangesetConfig] = DeployBurnMintERC20Transparent
Copy link
Contributor

@simsonraj simsonraj Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this to the changeset v2 version instead of legacy, separate apply & validate methods, would be easier to work with orchestrator changesets ( i think)

for token, config := range tokens {
if config.PreMint == nil {
config.PreMint = big.NewInt(0)
tokens[token] = config
Copy link
Contributor

@simsonraj simsonraj Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be ideal if we dont instantiate config in the validate method, we have had trouble before with similar patterns in the Token Pool deployments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We intentionally left PreMint as optional. Although we don't plan to use it ourselves (ever), we want to support the feature for potential clients. Keeping it optional allows us to satisfy those edge cases without complicating the default deployment.

"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"

"github.com/smartcontractkit/ccip-contract-examples/chains/evm/gobindings/generated/latest/token_governor"
"github.com/smartcontractkit/ccip-contract-examples/chains/evm/gobindings/generated/1_6_1/token_governor"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, did not know when the latest one was added

return r, nil
}

return [32]byte{}, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to return error for default case instead of empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, I will add error and remove check if it returns [32]byte32{}.

state.SignerRegistry = signerRegistry
state.ABIByAddress[address] = signer_registry.SignerRegistryABI
case cldf.NewTypeAndVersion(ccipshared.TransparentUpgradeableProxy, deployment.Version1_6_1).String():
token, err := burn_mint_erc20_transparent.NewBurnMintERC20Transparent(common.HexToAddress(address), chain.Client)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it mandatory to have a NewBurnMintERC20Transparent associated with TransparentUpgradeableProxy?
it seems the deploy function of TransparentUpgradeableProxy could have deployment independent of NewBurnMintERC20Transparent with !initialize?
we may have to solidify this assumption

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @simsonraj, let me try to explain the reasoning behind it and if we need to make loading state differently.

  1. The Implementation (BurnMintERC20Transparent): This contract serves purely as a logic library. Its own storage is never initialized, so if we query it directly, symbol() returns an empty string.
  2. The ProxyAdmin: This contract is strictly for administrative tasks (upgrades) and does not store any token metadata (like the symbol).

Because neither of these contracts holds the state (only the TUP Proxy does), we cannot fetch the symbol from them directly during state loading. I am using EIP-1967 storage slot lookups on the Proxy to deterministically link these addresses together, as that is the only reliable on-chain method to associate them without relying on event logs."

@cl-sonarqube-production
Copy link

@athegaul athegaul added this pull request to the merge queue Feb 4, 2026
Merged via the queue into develop with commit 43e1e86 Feb 4, 2026
262 of 267 checks passed
@athegaul athegaul deleted the CCIP-9118/add-transparent-upgradable-proxy branch February 4, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants