Documentation Index Fetch the complete documentation index at: https://docs.tac.build/llms.txt
Use this file to discover all available pages before exploring further.
TAC provides TacProxyV1Upgradeable for contracts that need to be upgraded after deployment. Use this base contract when you need upgrade functionality.
Basic Upgradeable Structure
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28 ;
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol" ;
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol" ;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol" ;
import { TacProxyV1Upgradeable } from "@tonappchain/evm-ccl/contracts/proxies/TacProxyV1Upgradeable.sol" ;
import { TacHeaderV1 } from "@tonappchain/evm-ccl/contracts/core/Structs.sol" ;
contract MyUpgradeableProxy is
Initializable ,
OwnableUpgradeable ,
UUPSUpgradeable ,
TacProxyV1Upgradeable
{
// Your state variables go here
mapping ( string => uint256 ) public userBalances;
uint256 public totalProcessed;
/// @custom:oz -upgrades-unsafe-allow constructor
constructor () {
_disableInitializers ();
}
function initialize ( address owner , address crossChainLayer )
public
initializer
{
__UUPSUpgradeable_init ();
__Ownable_init (owner);
__TacProxyV1Upgradeable_init (crossChainLayer);
// Initialize your contract state
totalProcessed = 0 ;
}
function _authorizeUpgrade ( address newImplementation )
internal
override
onlyOwner
{}
// Your proxy functions go here
function processRequest ( bytes calldata tacHeader , bytes calldata arguments )
external
_onlyCrossChainLayer
{
TacHeaderV1 memory header = _decodeTacHeader (tacHeader);
uint256 amount = abi . decode (arguments, ( uint256 ));
userBalances[header.tvmCaller] += amount;
totalProcessed += amount;
emit RequestProcessed (header.tvmCaller, amount);
}
event RequestProcessed ( string indexed user , uint256 amount );
}
Key Difference from Basic Contracts
The inheritance order is critical and must follow OpenZeppelin’s recommended pattern.
contract MyUpgradeableProxy is
Initializable , // Must be first
OwnableUpgradeable , // Access control
UUPSUpgradeable , // Upgrade mechanism
TacProxyV1Upgradeable // TAC functionality ( last )
Deployment
Deployment differs from the basic example. UUPS pattern is used in the example below:
import { Signer } from "ethers" ;
import { MyUpgradeableProxy } from "../../typechain-types" ;
import { deployUpgradable } from '@tonappchain/evm-ccl'
import { DeployProxyOptions } from "@openzeppelin/hardhat-upgrades/dist/utils" ;
import hre from 'hardhat' ;
const proxyOptsUUPS : DeployProxyOptions = {
kind: "uups" ,
unsafeAllow: [ "constructor" ]
};
export async function deployMyUpgradeableProxy (
deployer : Signer ,
crossChainLayerAddress : string ,
owner ?: string ,
) : Promise < MyUpgradeableProxy > {
const myUpgradeableProxy = await deployUpgradable < MyUpgradeableProxy >(
deployer ,
hre . artifacts . readArtifactSync ( 'MyUpgradeableProxy' ),
[ owner || await deployer . getAddress (), crossChainLayerAddress ],
proxyOptsUUPS ,
undefined ,
true // verbose
);
await myUpgradeableProxy . waitForDeployment ();
return myUpgradeableProxy ;
}
main (). catch ( console . error );
What’s Next?
Advanced Custom Proxy Learn even more sophisticated development patterns