// Source: contracts/utils/TokenManagerDeployer.sol pragma solidity ^0.8.0; // SPDX-License-Identifier: MIT // File @axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IProxy.sol@v6.0.4 // General interface for upgradable contracts interface IProxy { error InvalidOwner(); error InvalidImplementation(); error SetupFailed(); error NotOwner(); error AlreadyInitialized(); function implementation() external view returns (address); function setup(bytes calldata setupParams) external; } // File @axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/BaseProxy.sol@v6.0.4 /** * @title BaseProxy Contract * @dev This abstract contract implements a basic proxy that stores an implementation address. Fallback function * calls are delegated to the implementation. This contract is meant to be inherited by other proxy contracts. */ abstract contract BaseProxy is IProxy { // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; // keccak256('owner') bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0; /** * @dev Returns the current implementation address. * @return implementation_ The address of the current implementation contract */ function implementation() public view virtual returns (address implementation_) { assembly { implementation_ := sload(_IMPLEMENTATION_SLOT) } } /** * @dev Shadows the setup function of the implementation contract so it can't be called directly via the proxy. * @param params The setup parameters for the implementation contract. */ function setup(bytes calldata params) external {} /** * @dev Returns the contract ID. It can be used as a check during upgrades. Meant to be implemented in derived contracts. * @return bytes32 The contract ID */ function contractId() internal pure virtual returns (bytes32); /** * @dev Fallback function. Delegates the call to the current implementation contract. */ fallback() external payable virtual { address implementation_ = implementation(); assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), implementation_, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } /** * @dev Payable fallback function. Can be overridden in derived contracts. */ receive() external payable virtual {} } // File contracts/interfaces/ITokenManagerProxy.sol /** * @title ITokenManagerProxy Interface * @notice This interface is for a proxy for token manager contracts. */ interface ITokenManagerProxy is IProxy { error ZeroAddress(); /** * @notice Returns implementation type of this token manager. * @return uint256 The implementation type of this token manager. */ function implementationType() external view returns (uint256); /** * @notice Returns the interchain token ID of the token manager. * @return bytes32 The interchain token ID of the token manager. */ function interchainTokenId() external view returns (bytes32); /** * @notice Returns token address that this token manager manages. * @return address The token address. */ function tokenAddress() external view returns (address); /** * @notice Returns implementation type and token address. * @return uint256 The implementation type. * @return address The token address. */ function getImplementationTypeAndTokenAddress() external view returns (uint256, address); } // File contracts/interfaces/IBaseTokenManager.sol /** * @title IBaseTokenManager * @notice This contract is defines the base token manager interface implemented by all token managers. */ interface IBaseTokenManager { /** * @notice A function that returns the token id. */ function interchainTokenId() external view returns (bytes32); /** * @notice A function that should return the address of the token. * Must be overridden in the inheriting contract. * @return address address of the token. */ function tokenAddress() external view returns (address); /** * @notice A function that should return the token address from the init params. */ function getTokenAddressFromParams(bytes calldata params) external pure returns (address); } // File contracts/interfaces/ITokenManagerImplementation.sol /** * @title ITokenManagerImplementation Interface * @notice Interface for returning the token manager implementation type. */ interface ITokenManagerImplementation { /** * @notice Returns the implementation address for a given token manager type. * @param tokenManagerType The type of token manager. * @return tokenManagerAddress_ The address of the token manager implementation. */ function tokenManagerImplementation(uint256 tokenManagerType) external view returns (address tokenManagerAddress_); } // File contracts/proxies/TokenManagerProxy.sol /** * @title TokenManagerProxy * @notice This contract is a proxy for token manager contracts. * @dev This contract implements BaseProxy and ITokenManagerProxy. */ contract TokenManagerProxy is BaseProxy, ITokenManagerProxy { bytes32 private constant CONTRACT_ID = keccak256('token-manager'); address public immutable interchainTokenService; uint256 public immutable implementationType; bytes32 public immutable interchainTokenId; address public immutable tokenAddress; /** * @notice Constructs the TokenManagerProxy contract. * @param interchainTokenService_ The address of the interchain token service. * @param implementationType_ The token manager type. * @param tokenId The identifier for the token. * @param params The initialization parameters for the token manager contract. */ constructor(address interchainTokenService_, uint256 implementationType_, bytes32 tokenId, bytes memory params) { if (interchainTokenService_ == address(0)) revert ZeroAddress(); interchainTokenService = interchainTokenService_; implementationType = implementationType_; interchainTokenId = tokenId; address implementation_ = _tokenManagerImplementation(interchainTokenService_, implementationType_); if (implementation_ == address(0)) revert InvalidImplementation(); (bool success, ) = implementation_.delegatecall(abi.encodeWithSelector(IProxy.setup.selector, params)); if (!success) revert SetupFailed(); tokenAddress = IBaseTokenManager(implementation_).getTokenAddressFromParams(params); } /** * @notice Getter for the contract id. * @return bytes32 The contract id. */ function contractId() internal pure override returns (bytes32) { return CONTRACT_ID; } /** * @notice Returns implementation type and token address. * @return implementationType_ The implementation type. * @return tokenAddress_ The token address. */ function getImplementationTypeAndTokenAddress() external view returns (uint256 implementationType_, address tokenAddress_) { implementationType_ = implementationType; tokenAddress_ = tokenAddress; } /** * @notice Returns the address of the current implementation. * @return implementation_ The address of the current implementation. */ function implementation() public view override(BaseProxy, IProxy) returns (address implementation_) { implementation_ = _tokenManagerImplementation(interchainTokenService, implementationType); } /** * @notice Returns the implementation address from the interchain token service for the provided type. * @param interchainTokenService_ The address of the interchain token service. * @param implementationType_ The token manager type. * @return implementation_ The address of the implementation. */ function _tokenManagerImplementation( address interchainTokenService_, uint256 implementationType_ ) internal view returns (address implementation_) { implementation_ = ITokenManagerImplementation(interchainTokenService_).tokenManagerImplementation(implementationType_); } } // File @axelar-network/axelar-gmp-sdk-solidity/contracts/deploy/CreateDeploy.sol@v6.0.4 /** * @title CreateDeploy Contract * @notice This contract deploys new contracts using the `CREATE` opcode and is used as part of * the `CREATE3` deployment method. */ contract CreateDeploy { /** * @dev Deploys a new contract with the specified bytecode using the `CREATE` opcode. * @param bytecode The bytecode of the contract to be deployed */ // slither-disable-next-line locked-ether function deploy(bytes memory bytecode) external payable { assembly { if iszero(create(0, add(bytecode, 32), mload(bytecode))) { revert(0, 0) } } } } // File @axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IDeploy.sol@v6.0.4 /** * @title IDeploy Interface * @notice This interface defines the errors for a contract that is responsible for deploying new contracts. */ interface IDeploy { error EmptyBytecode(); error AlreadyDeployed(); error DeployFailed(); } // File @axelar-network/axelar-gmp-sdk-solidity/contracts/libs/ContractAddress.sol@v6.0.4 library ContractAddress { function isContract(address contractAddress) internal view returns (bool) { bytes32 existingCodeHash = contractAddress.codehash; // https://eips.ethereum.org/EIPS/eip-1052 // keccak256('') == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 return existingCodeHash != bytes32(0) && existingCodeHash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; } } // File contracts/utils/Create3AddressFixed.sol /** * @title Create3AddressFixed contract * @notice This contract can be used to predict the deterministic deployment address of a contract deployed with the `CREATE3` technique. * It is equivalent to the Create3Address found in axelar-gmp-sdk-solidity repo but uses a fixed bytecode for CreateDeploy, * which allows changing compilation options (like number of runs) without affecting the future deployment addresses. */ contract Create3AddressFixed { // slither-disable-next-line too-many-digits bytes internal constant CREATE_DEPLOY_BYTECODE = hex'608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001d5760003560e01c806277436014610022575b600080fd5b61003561003036600461007b565b610037565b005b8051602082016000f061004957600080fd5b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561008d57600080fd5b813567ffffffffffffffff808211156100a557600080fd5b818401915084601f8301126100b957600080fd5b8135818111156100cb576100cb61004c565b604051601f8201601f19908116603f011681019083821181831017156100f3576100f361004c565b8160405282815287602084870101111561010c57600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122094780ce55d28f1d568f4e0ab1b9dc230b96e952b73d2e06456fbff2289fa27f464736f6c63430008150033'; bytes32 internal constant CREATE_DEPLOY_BYTECODE_HASH = keccak256(CREATE_DEPLOY_BYTECODE); /** * @notice Compute the deployed address that will result from the `CREATE3` method. * @param deploySalt A salt to influence the contract address * @return deployed The deterministic contract address if it was deployed */ function _create3Address(bytes32 deploySalt) internal view returns (address deployed) { address deployer = address( uint160(uint256(keccak256(abi.encodePacked(hex'ff', address(this), deploySalt, CREATE_DEPLOY_BYTECODE_HASH)))) ); deployed = address(uint160(uint256(keccak256(abi.encodePacked(hex'd6_94', deployer, hex'01'))))); } } // File contracts/utils/Create3Fixed.sol /** * @title Create3Fixed contract * @notice This contract can be used to deploy a contract with a deterministic address that depends only on * the deployer address and deployment salt, not the contract bytecode and constructor parameters. * It uses a fixed bytecode to allow changing the compilation settings without affecting the deployment address in the future. */ contract Create3Fixed is Create3AddressFixed, IDeploy { using ContractAddress for address; /** * @notice Deploys a new contract using the `CREATE3` method. * @dev This function first deploys the CreateDeploy contract using * the `CREATE2` opcode and then utilizes the CreateDeploy to deploy the * new contract with the `CREATE` opcode. * @param bytecode The bytecode of the contract to be deployed * @param deploySalt A salt to influence the contract address * @return deployed The address of the deployed contract */ function _create3(bytes memory bytecode, bytes32 deploySalt) internal returns (address deployed) { deployed = _create3Address(deploySalt); if (bytecode.length == 0) revert EmptyBytecode(); if (deployed.isContract()) revert AlreadyDeployed(); // Deploy using create2 CreateDeploy createDeploy; bytes memory createDeployBytecode_ = CREATE_DEPLOY_BYTECODE; uint256 length = createDeployBytecode_.length; assembly { createDeploy := create2(0, add(createDeployBytecode_, 0x20), length, deploySalt) } if (address(createDeploy) == address(0)) revert DeployFailed(); // Deploy using create createDeploy.deploy(bytecode); } } // File contracts/interfaces/ITokenManagerDeployer.sol /** * @title ITokenManagerDeployer Interface * @notice This interface is used to deploy new instances of the TokenManagerProxy contract. */ interface ITokenManagerDeployer { error TokenManagerDeploymentFailed(); /** * @notice Deploys a new instance of the TokenManagerProxy contract. * @param tokenId The token ID. * @param implementationType Token manager implementation type. * @param params Additional parameters used in the setup of the token manager. * @return tokenManager Address of the deployed tokenManager. */ function deployTokenManager( bytes32 tokenId, uint256 implementationType, bytes calldata params ) external payable returns (address tokenManager); } // File contracts/utils/TokenManagerDeployer.sol /** * @title TokenManagerDeployer * @notice This contract is used to deploy new instances of the TokenManagerProxy contract. */ contract TokenManagerDeployer is ITokenManagerDeployer, Create3Fixed { /** * @notice Deploys a new instance of the TokenManagerProxy contract * @param tokenId The unique identifier for the token * @param implementationType Token manager implementation type * @param params Additional parameters used in the setup of the token manager * @return tokenManager The address of the deployed tokenManager */ // slither-disable-next-line locked-ether function deployTokenManager( bytes32 tokenId, uint256 implementationType, bytes calldata params ) external payable returns (address tokenManager) { bytes memory args = abi.encode(address(this), implementationType, tokenId, params); // slither-disable-next-line too-many-digits bytes memory bytecode = abi.encodePacked(type(TokenManagerProxy).creationCode, args); tokenManager = _create3(bytecode, tokenId); if (tokenManager.code.length == 0) revert TokenManagerDeploymentFailed(); } }