// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../../ImplBase.sol";
import "../../helpers/errors.sol";
import "../../interfaces/optimism.sol";

/**
// @title Native Optimism Bridge Implementation.
// @author Socket Technology.
*/
contract NativeOptimismImpl is ImplBase, ReentrancyGuard {
    using SafeERC20 for IERC20;

    /**
    // @notice We set all the required addresses in the constructor while deploying the contract.
    // These will be constant addresses.
    // @dev Please use the Proxy addresses and not the implementation addresses while setting these 
    // @param _registry address of the registry contract that calls this contract
    */
    constructor(address _registry) ImplBase(_registry) {}

    /**
    // @param _amount amount to be sent.
    // @param _from sending address.
    // @param _receiverAddress receiving address.
    // @param _token address of the token to be bridged to optimism.
     */
    function outboundTransferTo(
        uint256 _amount,
        address _from,
        address _receiverAddress,
        address _token,
        uint256,
        bytes memory _extraData
    ) external payable override onlyRegistry nonReentrant {
        OptimismBridgeExtraData memory _optimismBridgeExtraData = abi.decode(
            _extraData,
            (OptimismBridgeExtraData)
        );
        require(
            _optimismBridgeExtraData._interfaceId != 0,
            MovrErrors.UNSUPPORTED_INTERFACE_ID
        );
        if (_token == NATIVE_TOKEN_ADDRESS) {
            require(msg.value != 0, MovrErrors.VALUE_SHOULD_NOT_BE_ZERO);
            L1StandardBridge(_optimismBridgeExtraData._customBridgeAddress)
                .depositETHTo{value: _amount}(
                _receiverAddress,
                _optimismBridgeExtraData._l2Gas,
                _optimismBridgeExtraData._data
            );
            return;
        }
        require(msg.value == 0, MovrErrors.VALUE_SHOULD_BE_ZERO);
        IERC20 token = IERC20(_token);
        // set allowance for erc20 predicate
        token.safeTransferFrom(_from, address(this), _amount);
        token.safeIncreaseAllowance(
            _optimismBridgeExtraData._customBridgeAddress,
            _amount
        );

        if (_optimismBridgeExtraData._interfaceId == 1) {
            // deposit into standard bridge
            L1StandardBridge(_optimismBridgeExtraData._customBridgeAddress)
                .depositERC20To(
                    _token,
                    _optimismBridgeExtraData._l2Token,
                    _receiverAddress,
                    _amount,
                    _optimismBridgeExtraData._l2Gas,
                    _optimismBridgeExtraData._data
                );
            return;
        }

        // Deposit Using Old Standard - iOVM_L1TokenGateway(Example - SNX Token)
        if (_optimismBridgeExtraData._interfaceId == 2) {
            OldL1TokenGateway(_optimismBridgeExtraData._customBridgeAddress)
                .depositTo(_receiverAddress, _amount);
        }

        if (_optimismBridgeExtraData._interfaceId == 3) {
            OldL1TokenGateway(_optimismBridgeExtraData._customBridgeAddress)
                .initiateSynthTransfer(
                    _optimismBridgeExtraData._currencyKey,
                    _receiverAddress,
                    _amount
                );
        }
    }
}
[{"inputs":[{"internalType":"address","name":"_registry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registryAddress","type":"address"}],"name":"UpdateRegistryAddress","type":"event"},{"inputs":[],"name":"NATIVE_TOKEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_receiverAddress","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"outboundTransferTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"userAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRegistry","type":"address"}],"name":"updateRegistryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]