// File: @axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// General interface for upgradable contracts
interface IContractIdentifier {
    /**
     * @notice Returns the contract ID. It can be used as a check during upgrades.
     * @dev Meant to be overridden in derived contracts.
     * @return bytes32 The contract ID
     */
    function contractId() external pure returns (bytes32);
}

// File: @axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IProxy.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// 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



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IProxy } from '../interfaces/IProxy.sol';

/**
 * @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: @axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Proxy.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IProxy } from '../interfaces/IProxy.sol';
import { IContractIdentifier } from '../interfaces/IContractIdentifier.sol';
import { BaseProxy } from './BaseProxy.sol';

/**
 * @title Proxy Contract
 * @notice A proxy contract that delegates calls to a designated implementation contract. Inherits from BaseProxy.
 * @dev The constructor takes in the address of the implementation contract, the owner address, and any optional setup
 * parameters for the implementation contract.
 */
contract Proxy is BaseProxy {
    /**
     * @notice Constructs the proxy contract with the implementation address, owner address, and optional setup parameters.
     * @param implementationAddress The address of the implementation contract
     * @param owner The owner address
     * @param setupParams Optional parameters to setup the implementation contract
     * @dev The constructor verifies that the owner address is not the zero address and that the contract ID of the implementation is valid.
     * It then stores the implementation address and owner address in their designated storage slots and calls the setup function on the
     * implementation (if setup params exist).
     */
    constructor(
        address implementationAddress,
        address owner,
        bytes memory setupParams
    ) {
        if (owner == address(0)) revert InvalidOwner();

        bytes32 id = contractId();
        // Skipping the check if contractId() is not set by an inheriting proxy contract
        if (id != bytes32(0) && IContractIdentifier(implementationAddress).contractId() != id)
            revert InvalidImplementation();

        assembly {
            sstore(_IMPLEMENTATION_SLOT, implementationAddress)
            sstore(_OWNER_SLOT, owner)
        }

        if (setupParams.length != 0) {
            (bool success, ) = implementationAddress.delegatecall(
                abi.encodeWithSelector(BaseProxy.setup.selector, setupParams)
            );
            if (!success) revert SetupFailed();
        }
    }

    function contractId() internal pure virtual override returns (bytes32) {
        return bytes32(0);
    }
}

// File: contracts/proxies/InterchainProxy.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Proxy } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Proxy.sol';

/**
 * @title InterchainProxy
 * @notice This contract is a proxy for interchainTokenService and interchainTokenFactory.
 * @dev This contract implements Proxy.
 */
contract InterchainProxy is Proxy {
    constructor(address implementationAddress, address owner, bytes memory setupParams) Proxy(implementationAddress, owner, setupParams) {}
}