<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sebastien Levy</title>
    <description>The latest articles on Forem by Sebastien Levy (@sebastien_levy_233585b9a3).</description>
    <link>https://forem.com/sebastien_levy_233585b9a3</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3595909%2F1c8ccfe9-c4f7-460a-a245-c84d8ee33fd0.png</url>
      <title>Forem: Sebastien Levy</title>
      <link>https://forem.com/sebastien_levy_233585b9a3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sebastien_levy_233585b9a3"/>
    <language>en</language>
    <item>
      <title>Deep Dive in Transparent Proxy Code</title>
      <dc:creator>Sebastien Levy</dc:creator>
      <pubDate>Fri, 07 Nov 2025 10:01:26 +0000</pubDate>
      <link>https://forem.com/sebastien_levy_233585b9a3/deep-dive-in-transparent-proxy-code-2o45</link>
      <guid>https://forem.com/sebastien_levy_233585b9a3/deep-dive-in-transparent-proxy-code-2o45</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In a &lt;a href="https://dev.to/sebastien_levy_233585b9a3/understanding-solidity-transparent-upgradeable-proxy-pattern-a-practical-guide-1abm"&gt;previous article&lt;/a&gt; I made a presentation on Transparent Upgradeable Proxies in Solidity; what they are, why they are useful and key concepts about how they work.&lt;/p&gt;

&lt;p&gt;I let readers to dive in at their leisure in the code in &lt;a href="https://github.com/MetaBarj0/Nifty" rel="noopener noreferrer"&gt;this repository&lt;/a&gt; should they wish to know more.&lt;/p&gt;

&lt;p&gt;I had some feedback though telling me it could be valuable to expose this proxy implementation code alongside precise explanations about how it works.&lt;/p&gt;

&lt;p&gt;So here we are, 100% proxy, 100% focus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Let's keep something that is working by taking some code from &lt;a href="https://github.com/MetaBarj0/Nifty" rel="noopener noreferrer"&gt;The Nifty&lt;/a&gt; repository :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/MetaBarj0/Nifty/blob/main/contracts/src/proxy/TransparentUpgradeableProxy.sol" rel="noopener noreferrer"&gt;TransparentUpgradeableProxy.sol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MetaBarj0/Nifty/blob/main/contracts/src/proxy/ProxyStorage.sol" rel="noopener noreferrer"&gt;ProxyStorage.sol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Study of TransparentUpgradeableProxy.sol
&lt;/h2&gt;

&lt;p&gt;This is the actual transparent proxy implementation.&lt;br&gt;
In this section I'll make a parallel between concepts I exposed in &lt;a href="https://dev.to/sebastien_levy_233585b9a3/understanding-solidity-transparent-upgradeable-proxy-pattern-a-practical-guide-1abm"&gt;this article&lt;/a&gt; and the actual code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Storage Slots
&lt;/h3&gt;

&lt;p&gt;I've talked about storage slot management, in particular, storage slots collision.&lt;br&gt;
Remember, a proxy call effectively calls an underlying implementation contract function but all state management is done within the proxy. This is the basis of how &lt;code&gt;delegatecall&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;You see, this proxy implementation has also some states to manage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the address of the current &lt;code&gt;administrator&lt;/code&gt; of the proxy&lt;/li&gt;
&lt;li&gt;the address of the current &lt;code&gt;implementation&lt;/code&gt; contract to call functions of.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those states were declared as they are in the implementation contract (or any normal contract), they would collide together and things would get very hot, very soon.&lt;/p&gt;

&lt;p&gt;But wait... there are no state member within this proxy contract.&lt;/p&gt;

&lt;p&gt;The only thing you have are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;weird constants whose values are provided (for gas optimizations)&lt;/li&gt;
&lt;li&gt;a modifier and functions using those weird constants through a weird type named &lt;code&gt;ProxyStorage&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Weird constants
&lt;/h4&gt;

&lt;p&gt;You can see they are result of hashing a string. In fact, the result of this hashing will give us the slot number where to store state of this proxy.&lt;/p&gt;

&lt;p&gt;Therefore, &lt;code&gt;ADMIN_SLOT&lt;/code&gt; will be the slot where we'll store the address of the proxy admin and &lt;code&gt;IMPLEMENTATION_SLOT&lt;/code&gt;, the slot where we'll store the current underlying implenetation contract.&lt;/p&gt;
&lt;h4&gt;
  
  
  The library
&lt;/h4&gt;

&lt;p&gt;Let's take a look at the &lt;a href="https://github.com/MetaBarj0/Nifty/blob/main/contracts/src/proxy/ProxyStorage.sol" rel="noopener noreferrer"&gt;ProxyStorage.sol&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;It defines a solidity &lt;code&gt;library&lt;/code&gt;. A &lt;code&gt;library&lt;/code&gt; can be seen as a base contract whose exposed function are &lt;code&gt;delegatecall&lt;/code&gt;ed somehow, allowing those called function to modify the state of the caller contract (&lt;a href="https://docs.soliditylang.org/en/v0.8.30/contracts.html#libraries" rel="noopener noreferrer"&gt;libraries in solidity&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This library only expose one function which gives us a reference on a stored struct object.&lt;/p&gt;

&lt;p&gt;Keep in mind the &lt;code&gt;stored struct object&lt;/code&gt; lies in the caller contracts in our case: &lt;code&gt;TransparentUpgradeableProxy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This function is quite low level as it uses inlined &lt;code&gt;assembly&lt;/code&gt; directive.&lt;br&gt;
This is to override the default compiler behavior.&lt;br&gt;
By default, the compiler store states of the contract at the first slot available starting at 0 and going forward (at leat for value types).&lt;br&gt;
With this function, we can choose the slot (the location) of the &lt;code&gt;TransparentUpgrageableProxy&lt;/code&gt; state variables thus, avoiding collisions with underlying implementation contract whose layout is deduced by the compiler default behavior I told just before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assembly ("memory-safe") { // memory-safe indeed, we just change a slot number
      r.slot := slot // define the slot number of the returned struct object
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, in the transparent proxy implementation a function such as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getAdmin_() private view returns (address) {
    // returns the value (address) stored in the ADMIN_SLOT slot number
    return ProxyStorage.getAddressSlot(ADMIN_SLOT).value;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ensures we do not collide with any underlying implementation contract state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Call delegation
&lt;/h3&gt;

&lt;p&gt;This key concept of transparent proxy deserves a bit of explanation.&lt;br&gt;
To put simply, the proxy effectively use of delegatecall but it is fine tuned for several reasons. Let's explore them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gas efficiency

&lt;ul&gt;
&lt;li&gt;Any, I say &lt;strong&gt;any&lt;/strong&gt; non-admin function calls to an underlying implementation contract pass through the proxy. Gas saving is paramount. This is why &lt;code&gt;assembly&lt;/code&gt; construct is used here as we'll see&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;call delegation through &lt;code&gt;fallback&lt;/code&gt; function

&lt;ul&gt;
&lt;li&gt;The fallback function is a particular beast. It does not return any value. But proxy delegated calls must work with functions returning values. Once more, &lt;code&gt;assembly&lt;/code&gt; to the rescue!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;standardization

&lt;ul&gt;
&lt;li&gt;In fact, this implementation of delegated call is the same as the one in the &lt;a href="https://github.com/MetaBarj0/openzeppelin-contracts/blob/eb97fd3f153589bc4d7cd0c512956b18aa844cfd/contracts/proxy/Proxy.sol#L22" rel="noopener noreferrer"&gt;OpenZeppelin repository&lt;/a&gt;. Understand that it's a super standard way to implement transparent proxy. I did not invent anything new here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function fallback_(address implementationContract) private {
    // we'll see why in the next section about transparency
    require(msg.sender != getAdmin_(), InvalidAdminCall());

    assembly {
      // Copy msg.data.
      // gas saving (no bytes allocation)
      // no harm due to scratch pad over-writing because there is no solidity code after this inline assembly block
      calldatacopy(0x00, 0x00, calldatasize())

      // this is the actual delegatecall
      // Call the implementation.
      // offset 0 and size unknown
      let result := delegatecall(gas(), implementationContract, 0x00, calldatasize(), 0x00, 0x00)

      // copy return data starting from offset 0 using return data size we know at this point
      returndatacopy(0x00, 0x00, returndatasize())

      // either returns or revert, using return data size
      switch result
      case 0 { revert(0x00, returndatasize()) }
      default { return(0x00, returndatasize()) }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Transparency
&lt;/h3&gt;

&lt;p&gt;In this project, the proxy must behave differently depending who's using it. Put simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the sender is the proxy &lt;code&gt;admin&lt;/code&gt;, call proxy function without forwarding to the underlying implementation. Calling an unexisting function leads to revert.&lt;/li&gt;
&lt;li&gt;If the sender is not the proxy &lt;code&gt;admin&lt;/code&gt;, delegate function call to the underlying implementation even if this function exists in the proxy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the code, this is represented by the &lt;code&gt;onlyAdmin&lt;/code&gt; modifier used in proxy getter functions (&lt;code&gt;admin&lt;/code&gt; and &lt;code&gt;implementation&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modifier onlyAdmin() {
    if (getAdmin_() == msg.sender) {
      _; // call of the proxy function
    } else {
      // delegatecall to underlying implementation      
      fallback_(ProxyStorage.getAddressSlot(IMPLEMENTATION_SLOT).value);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some experts reader might say writing modifier like this is an anti-pattern. I understand. Specify &lt;code&gt;if-else&lt;/code&gt; construct might obscure the intent of such modifier this is true. But in my case, I find it acceptable and it removes duplication; proxy are truly very specific and this code is not intended to change a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this deep tech dive into transparent proxy code is clear.&lt;br&gt;
I'd like to remind you though this implementation is functional, it is largely imperfect and can be enhanced a lot. Always prefer stardardized solution such as &lt;a href="https://github.com/MetaBarj0/openzeppelin-contracts/tree/master" rel="noopener noreferrer"&gt;Open Zeppelin&lt;/a&gt; for your proxy needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/christopherkade"&gt;@christopherkade&lt;/a&gt; for it's banner generator&lt;/li&gt;
&lt;li&gt;Open Zeppelin hard work that inspired me&lt;/li&gt;
&lt;li&gt;Ethereum ecosystem and community for the hard work they have been providing.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ethereum</category>
      <category>solidity</category>
      <category>smartcontract</category>
    </item>
    <item>
      <title>How to deploy you NFT on Sepolia - Simple and 100% under control</title>
      <dc:creator>Sebastien Levy</dc:creator>
      <pubDate>Thu, 06 Nov 2025 15:45:54 +0000</pubDate>
      <link>https://forem.com/sebastien_levy_233585b9a3/how-to-deploy-you-nft-on-sepolia-simple-and-100-under-control-245d</link>
      <guid>https://forem.com/sebastien_levy_233585b9a3/how-to-deploy-you-nft-on-sepolia-simple-and-100-under-control-245d</guid>
      <description>&lt;p&gt;In a previous article about &lt;a href="https://dev.to/sebastien_levy_233585b9a3/understanding-solidity-transparent-upgradeable-proxy-pattern-a-practical-guide-1abm"&gt;Transparent Upgradeable Proxy&lt;/a&gt; in solidity, I showed how this pattern has been used in a real NFT project.&lt;/p&gt;

&lt;p&gt;In this article, let's focus on how this kind of project can easily and efficiently be deployed on a testnet to ensure it works well before jumping to mainnet.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why bother with testnets?
&lt;/h1&gt;

&lt;p&gt;Deploying smart contracts on a testnet offers several advantages over skipping this step entirely. Testnets provide a realistic simulation of the Ethereum Mainnet environment, allowing developers to test contract functionality, interactions, and user flows in a live blockchain setting without risking real funds.&lt;br&gt;
This enables thorough end-to-end testing and allows beta testers to evaluate the application under real-world conditions.&lt;/p&gt;

&lt;p&gt;In contrast, skipping testnet deployment means missing out on these critical validation steps. Without testing on a testnet, developers risk deploying untested logic to the mainnet, where bugs could lead to irreversible financial losses or security vulnerabilities.&lt;/p&gt;

&lt;p&gt;While local development networks are useful for initial testing, they do not fully replicate the behavior of the Ethereum Virtual Machine (EVM) or the dynamics of a live network, making testnet deployment a necessary intermediate step before mainnet release.&lt;/p&gt;

&lt;p&gt;You should not skip this kind of deployment for any serious project.&lt;/p&gt;

&lt;h1&gt;
  
  
  The project
&lt;/h1&gt;

&lt;p&gt;To illustrate, let's focus on the NFT project I've already talked about: &lt;a href="https://github.com/MetaBarj0/Nifty" rel="noopener noreferrer"&gt;Nifty&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a complete NFT project thoroughly tested and able to be deployed at will on sepolia, provided you have the necessary API key from &lt;a href="https://etherscan.io/" rel="noopener noreferrer"&gt;etherscan&lt;/a&gt;, a node provider &lt;a href="https://www.alchemy.com/" rel="noopener noreferrer"&gt;for instance alchemy&lt;/a&gt; giving you an access to the test network as well as test ethers you can obtain from a faucet &lt;a href="https://faucets.chain.link/sepolia" rel="noopener noreferrer"&gt;such as chainlink&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tooling used
&lt;/h2&gt;

&lt;p&gt;Developping and deploying a blockchain project has never been so easy with todays's tooling.&lt;/p&gt;

&lt;p&gt;Though you've to keep in mind that some configuration is necessary, in this article I'll briefly cover 2 tools I use on an every day basis when I develop blockchain projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;Must have. &lt;a href="https://getfoundry.sh/introduction/getting-started" rel="noopener noreferrer"&gt;Foundry&lt;/a&gt; is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nideovim
&lt;/h3&gt;

&lt;p&gt;A tool &lt;a href="https://github.com/MetaBarj0/nideovim" rel="noopener noreferrer"&gt;I made&lt;/a&gt;.&lt;br&gt;
You can see it as an attempt to provide isolated and deterministic development environments for any kind of project.&lt;br&gt;
It combines the power of several well-known technologies such as Linux, Docker and Neovim that are fuelled by an evergrowing community that get them more and more powerful.&lt;/p&gt;

&lt;p&gt;I'll do a dedicated article on &lt;a href="https://github.com/MetaBarj0/nideovim" rel="noopener noreferrer"&gt;nideovim&lt;/a&gt; should you be interested (let me know in comments).&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup before deployments
&lt;/h1&gt;

&lt;p&gt;Let keep things simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git clone https://github.com/MetaBarj0/Nifty.git&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;code&gt;contracts&lt;/code&gt; directory:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cd contracts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ensure the project can be deployed by running tests:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;make test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;everything should be green&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Edit the &lt;code&gt;.env&lt;/code&gt; configuration file to allow deployement on the test network:

&lt;ul&gt;
&lt;li&gt;set the &lt;code&gt;MAINNET_URL&lt;/code&gt; variable to a RPC endpoint of your chosing (I use &lt;a href="https://www.alchemy.com/" rel="noopener noreferrer"&gt;alchemy&lt;/a&gt; as a node provider but any other can do)&lt;/li&gt;
&lt;li&gt;set the &lt;code&gt;SEPOLIA_URL&lt;/code&gt; variable using the same way as for the &lt;code&gt;MAINNET_URL&lt;/code&gt; variable.&lt;/li&gt;
&lt;li&gt;set the &lt;code&gt;MAINNET_FORK_BLOCK&lt;/code&gt; to a valid block number for instance &lt;code&gt;23739277&lt;/code&gt; but any valid block number is ok. You can get a valid block number of the homepage of &lt;a href="https://etherscan.io/" rel="noopener noreferrer"&gt;etherscan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;setup the &lt;code&gt;PRIVATE_KEY&lt;/code&gt; variable using the private key of a wallet containing enough test &lt;code&gt;ETH&lt;/code&gt; to deploy the contract. (&lt;strong&gt;NEVER EVER&lt;/strong&gt; use a wallet containing other non test token, you should have a test wallet for these kind of purposes)&lt;/li&gt;
&lt;li&gt;setup the &lt;code&gt;ETHERSCAN_API_KEY&lt;/code&gt; to an &lt;a href="https://etherscan.io/" rel="noopener noreferrer"&gt;etherscan&lt;/a&gt; API key you or your organization own (you can create one for free).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it for tedious configuration steps. The next part is the actual deployment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Simply deploy
&lt;/h1&gt;

&lt;p&gt;Only one command to rule the deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;make sepolia_deploy&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will deploy the entire set of smart contract to &lt;code&gt;sepolia&lt;/code&gt; that are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The NFT (Nifty contract)&lt;/li&gt;
&lt;li&gt;The crowd sale (Crowdsale contract)&lt;/li&gt;
&lt;li&gt;a pair of proxies (TransparentUpgradeableProxy contract)

&lt;ul&gt;
&lt;li&gt;one for Nifty contract&lt;/li&gt;
&lt;li&gt;one for the Crowdsale contract&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This step can take few minutes to complete. Once it's successful, you should see something like &lt;code&gt;All (4) contracts were verified!&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Etherscan post deploy steps
&lt;/h1&gt;

&lt;p&gt;As I said, 4 contracts have been deployed and 2 of them are proxies. The next things to do is to get the 2 proxies deployed contract addresses and tell to &lt;code&gt;sepolia&lt;/code&gt; that those contract are proxies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the contract addresses
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to the broadcast deployment directory: &lt;code&gt;cd broadcast/SepoliaDeploy.s.sol/11155111&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;look into the &lt;code&gt;run-latest.json&lt;/code&gt; file to get addresses of the 2 proxy contracts:

&lt;ul&gt;
&lt;li&gt;look for these 2 lines in the file : &lt;code&gt;"contractName": "TransparentUpgradeableProxy"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;get the 2 addresses in the field: &lt;code&gt;contractAddress&lt;/code&gt; of the object you found.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setup proxies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://sepolia.etherscan.io/" rel="noopener noreferrer"&gt;sepolia etherscan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;in the search bar, put one of the 2 addresses you got from &lt;code&gt;run-latest.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;go to the &lt;code&gt;contract&lt;/code&gt; tab&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sepolia etherscan&lt;/code&gt; should tell you this contract may be a proxy (and he's right)&lt;/li&gt;
&lt;li&gt;then setup this contract as a proxy

&lt;ul&gt;
&lt;li&gt;at the right of the &lt;code&gt;contract source code&lt;/code&gt; line there is a &lt;code&gt;more options&lt;/code&gt; dropdown, click on it.&lt;/li&gt;
&lt;li&gt;click on &lt;code&gt;is this a proxy?&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;on the new page click on &lt;code&gt;verify&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;once done you'll get notified the address of the implementation contract&lt;/li&gt;
&lt;li&gt;click &lt;code&gt;save&lt;/code&gt; and go back to the proxy contract page&lt;/li&gt;
&lt;li&gt;repeat the same process for the other proxy&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment done
&lt;/h2&gt;

&lt;p&gt;Once those steps are done, in the contract tab you can see 2 new buttons: &lt;code&gt;read as proxy&lt;/code&gt; and &lt;code&gt;write as proxy&lt;/code&gt; allowing you to interact with the proxy contract as if it were the underlying implementation contract (Nifty or Crowdsale).&lt;/p&gt;

&lt;h1&gt;
  
  
  Next steps
&lt;/h1&gt;

&lt;p&gt;Now contracts have been deployed on a public test net, you can interact with them freely using any mean (RPC endpoint using a Node provider, Remix IDE, ...)&lt;/p&gt;

&lt;h2&gt;
  
  
  Play with deployed contracts
&lt;/h2&gt;

&lt;p&gt;As an exercise left to the reader, make few transactions to deployed contracts using Remix.&lt;/p&gt;

&lt;p&gt;I let you same addresses of a previous deployment I made here, should you have any issue deploying yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Nifty&lt;/code&gt; at &lt;code&gt;0x4a6e3713ce9cc0b18de00e195a0d6ab4d09c2175&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Crowdsale&lt;/code&gt; at &lt;code&gt;0xe51979cea418896991f17e7a432db652094d6271&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Nifty proxy&lt;/code&gt; at &lt;code&gt;0xdb03331289ceae8ceb3ca9d3888c45d24e5b72a4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Crowdsale proxy&lt;/code&gt; at &lt;code&gt;0xc2c46f98946b5373b489542f07f42e1993020821&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this article has been clear enough and is relevant enough to prove you can deploy projects on test nets to ensure things are going well before deploying it to main net.&lt;/p&gt;

&lt;p&gt;Let me know about your thoughts in comment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Thanks
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/christopherkade"&gt;@christopherkade&lt;/a&gt; for it's banner generator&lt;/li&gt;
&lt;li&gt;Brave Leo's AI to have helped me to build arguments chapter regarding why bother about deploying on test net&lt;/li&gt;
&lt;li&gt;contributor to fantastic dev tools I use every day to build.&lt;/li&gt;
&lt;li&gt;all the community for all invaluable resources I consume every day to be able to make something eventually useful&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>blockchain</category>
      <category>ethereum</category>
      <category>smartcontract</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Understanding Solidity Transparent Upgradeable Proxy Pattern - A Practical Guide</title>
      <dc:creator>Sebastien Levy</dc:creator>
      <pubDate>Tue, 04 Nov 2025 14:56:52 +0000</pubDate>
      <link>https://forem.com/sebastien_levy_233585b9a3/understanding-solidity-transparent-upgradeable-proxy-pattern-a-practical-guide-1abm</link>
      <guid>https://forem.com/sebastien_levy_233585b9a3/understanding-solidity-transparent-upgradeable-proxy-pattern-a-practical-guide-1abm</guid>
      <description>&lt;p&gt;Smart contract development presents a unique challenge: once deployed to the&lt;br&gt;
blockchain, your code becomes immutable. This immutability, while providing&lt;br&gt;
security and trust guarantees, creates significant difficulties when you need&lt;br&gt;
to upgrade your contract logic or fix critical vulnerabilities. Enter the&lt;br&gt;
&lt;strong&gt;Transparent Upgradeable Proxy Pattern&lt;/strong&gt; - an elegant solution that allows&lt;br&gt;
smart contracts to be upgraded while maintaining their state and address.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Immutability Challenge
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Smart Contracts Can't Be Changed
&lt;/h3&gt;

&lt;p&gt;When you deploy a smart contract to Ethereum or any EVM-compatible blockchain,&lt;br&gt;
the bytecode is permanently stored on the blockchain. This immutability&lt;br&gt;
provides several benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust&lt;/strong&gt;: Users can verify the contract code and know it won't change unexpectedly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: No single party can maliciously modify the contract logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decentralization&lt;/strong&gt;: The contract operates independently without central control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this immutability creates significant challenges:&lt;/p&gt;

&lt;h3&gt;
  
  
  Difficulties in Upgrading Smart Contract Logic
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bug Fixes&lt;/strong&gt;: If you discover a critical bug in your contract, you can't
simply patch it like traditional software&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature Updates&lt;/strong&gt;: Adding new functionality requires deploying a
completely new contract&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Migration&lt;/strong&gt;: Moving user data from old contracts to new ones is
complex and expensive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address Changes&lt;/strong&gt;: A new deployment means a new contract address, breaking
integrations and user bookmarks&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Vulnerability Problem
&lt;/h3&gt;

&lt;p&gt;Consider this scenario: You've deployed a popular DeFi protocol with millions&lt;br&gt;
of dollars locked in it. Suddenly, a security researcher discovers a critical&lt;br&gt;
vulnerability that could drain all funds. In traditional software, you'd push a&lt;br&gt;
hotfix immediately. But with immutable smart contracts, you're stuck with three&lt;br&gt;
bad options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deploy a new contract&lt;/strong&gt; - Users must migrate manually, often with
significant friction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live with the vulnerability&lt;/strong&gt; - Hope nobody exploits it while you work on
a migration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a kill switch&lt;/strong&gt; - Pause the contract, but this defeats the purpose of
decentralization&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enter the Transparent Upgradeable Proxy Pattern
&lt;/h2&gt;

&lt;p&gt;The proxy pattern solves these problems by separating &lt;strong&gt;storage&lt;/strong&gt; from&lt;br&gt;
&lt;strong&gt;logic&lt;/strong&gt;. Here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Proxy Contract&lt;/strong&gt;: Holds all the state/storage and delegates function calls
to the implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation Contract&lt;/strong&gt;: Contains the business logic but no state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin&lt;/strong&gt;: Can upgrade the implementation while preserving the proxy's state
and address&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Components
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Delegatecall&lt;/strong&gt;: The proxy uses &lt;code&gt;delegatecall&lt;/code&gt; to execute implementation
code in proxy's context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Slots&lt;/strong&gt;: Carefully managed to avoid collisions between proxy and
implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency&lt;/strong&gt;: Admin calls access proxy functions, user calls are
forwarded to implementation&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Building a Practical Implementation with Foundry
&lt;/h2&gt;

&lt;p&gt;Let's build a real-world transparent upgradeable proxy using Test-Driven&lt;br&gt;
Development (TDD) with Foundry. We'll use a practical example from an NFT&lt;br&gt;
contract system.&lt;/p&gt;

&lt;p&gt;To get a full grasp on the implementation, go to &lt;a href="https://github.com/MetaBarj0/Nifty" rel="noopener noreferrer"&gt;Nifty&lt;br&gt;
repository&lt;/a&gt;.&lt;br&gt;
All code examples here exist in this repository and you could test it and even&lt;br&gt;
deploy it on a test network if you want to play a bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  A first look
&lt;/h3&gt;

&lt;p&gt;When I start a project, one of the first thing I do is executing tests to see&lt;br&gt;
if everything is in order with a fresh clone on a new environment.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;Nifty&lt;/code&gt;, it's pretty simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;code&gt;contracts&lt;/code&gt; subdirectory and run: &lt;code&gt;make test&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything should be green.&lt;br&gt;
If not, please, report in comments and I'll do my best to get it in the right&lt;br&gt;
color for you.&lt;/p&gt;

&lt;p&gt;Now let's focus on the &lt;code&gt;contracts/test/proxy/TransparentUpgradeableProxy.t.sol&lt;/code&gt;&lt;br&gt;
file.&lt;/p&gt;

&lt;p&gt;Feel free to browse all tests in this suite but for now, let's focus on those&lt;br&gt;
that are designed to ensure the tricky part of the proxy are well implemented.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deep diving in most important cases
&lt;/h3&gt;

&lt;h4&gt;
  
  
  test_constructor_throws_withFailingInitializableImplementation
&lt;/h4&gt;

&lt;p&gt;This test ensures a TransparentUpgradeableProxy contract cannot be deployed if&lt;br&gt;
the underlying implementation fails to initialize with an existing &lt;code&gt;initialize&lt;/code&gt;&lt;br&gt;
function.&lt;/p&gt;

&lt;p&gt;This is very important because proxy deployments cannot use constructors to&lt;br&gt;
initialize their state. Thus, they rely on an initialization function that&lt;br&gt;
&lt;em&gt;MUST&lt;/em&gt; be in the implementation contract.&lt;/p&gt;

&lt;p&gt;In this test the implementation contract is&lt;br&gt;
&lt;code&gt;FailingInitializableImplementation&lt;/code&gt; located in the &lt;code&gt;contracts/test/Mocks.sol&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;initialize&lt;/code&gt; function just revert. As simple as that.&lt;/p&gt;

&lt;h4&gt;
  
  
  test_constructor_initializes_triviallyConstructibleContract
&lt;/h4&gt;

&lt;p&gt;Should the underlying implementation be simple enough to not have specific&lt;br&gt;
initialization logic, this test ensure a proxy can handle it. No call to an&lt;br&gt;
initialize function is needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  test_admin_returnsProxyAdmin_ifAdmin
&lt;/h4&gt;

&lt;p&gt;The TransparentUpgradeableProxy pattern imposes specific behaviors regarding&lt;br&gt;
which function to call depending on who's calling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the sender is the proxy admin, there is no routing to underlying
implementation and proxy functions are directly called&lt;/li&gt;
&lt;li&gt;If the sender is someone else, a forward is done using &lt;code&gt;delegatecall&lt;/code&gt;. Proxy
functions will never be called. Should an in-existing function called, the
transaction is reverted.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  test_admin_returnsImplementationAdmin_ifNotAdmin
&lt;/h4&gt;

&lt;p&gt;The reciprocal of above, in this case, the test will call the &lt;code&gt;admin&lt;/code&gt; function&lt;br&gt;
of the implementation contract &lt;code&gt;TestImplementation&lt;/code&gt; located in&lt;br&gt;
&lt;code&gt;contracts/test/Mocks.sol&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  test_stateChangesOccurInProxyStorage_forNotAdminCalls
&lt;/h4&gt;

&lt;p&gt;This one ensures all state changes occur in the proxy slots instead of the&lt;br&gt;
implementation contract slots. This test also proves there is no collision&lt;br&gt;
between proxy storage slots and implementation contract storage slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  A real wold application: Nifty
&lt;/h3&gt;

&lt;p&gt;This ERC721 token implementation fully use the transparent upgradeable proxy&lt;br&gt;
pattern at its core. To get further, all features of this token (and also the&lt;br&gt;
associated Crowdsale contract) are tested both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;directly (using contract functions)&lt;/li&gt;
&lt;li&gt;through a transparent upgradeable proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Take a look in the &lt;code&gt;contracts/test/Nifty.t.sol&lt;/code&gt; for a very concise overview on&lt;br&gt;
how it works.&lt;/p&gt;

&lt;p&gt;A powerful Foundry feature is leveraged here: table testing, allowing to&lt;br&gt;
parameterize test.&lt;/p&gt;

&lt;p&gt;In a nutshell, each test is executed twice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;using the &lt;code&gt;Nifty&lt;/code&gt; contract directly&lt;/li&gt;
&lt;li&gt;by calling &lt;code&gt;Nifty&lt;/code&gt; contract functions through a proxy&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There would be so much to say about this fantastic pattern but I think I&lt;br&gt;
covered the most important aspects here.&lt;/p&gt;

&lt;p&gt;I hope this article could be seen as both a concise explanation on what&lt;br&gt;
transparent upgradeable proxies are in solidity and how to use them practically&lt;br&gt;
in a real world project using proven development methodologies.&lt;/p&gt;

&lt;p&gt;I'd love some feedbacks of the community to improve both this article and the&lt;br&gt;
&lt;code&gt;Nifty&lt;/code&gt; implementation.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>solidity</category>
      <category>smartcontract</category>
      <category>tdd</category>
    </item>
  </channel>
</rss>
