From 5fbda4d1af1180a3ad7c4930581380b9af9e9e99 Mon Sep 17 00:00:00 2001 From: Ruhum Date: Sat, 18 May 2024 19:09:50 +0300 Subject: [PATCH] feat(bridger): add XLayer bridger --- script/crosschain/DeployXLayerBridger.s.sol | 30 +++++++++++ vyper_contracts/bridgers/XLayerBridger.vy | 60 +++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 script/crosschain/DeployXLayerBridger.s.sol create mode 100644 vyper_contracts/bridgers/XLayerBridger.vy diff --git a/script/crosschain/DeployXLayerBridger.s.sol b/script/crosschain/DeployXLayerBridger.s.sol new file mode 100644 index 0000000..6efe433 --- /dev/null +++ b/script/crosschain/DeployXLayerBridger.s.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.13; + +import {CREATE3Script} from "../base/CREATE3Script.sol"; +import {VyperDeployer} from "../../src/lib/VyperDeployer.sol"; + +contract DeployXLayerBridgerScript is CREATE3Script, VyperDeployer { + constructor() CREATE3Script(vm.envString("VERSION")) {} + + function run() public returns (address bridger) { + uint256 deployerPrivateKey = uint256(vm.envBytes32("PRIVATE_KEY")); + vm.startBroadcast(deployerPrivateKey); + + address xLayerMainnetBridge = 0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe; + // 1 = XLayer testnet + // 3 = XLayer mainnet + // see https://www.okx.com/xlayer/docs/developer/build-on-xlayer/bridge-to-xlayer + uint32 networkId = 3; + + bridger = createx.deployCreate3( + getCreate3ContractSalt("XLayerBridger"), + bytes.concat( + compileContract("bridgers/XLayerBridger"), + abi.encode(vm.envAddress("oVCX"), xLayerMainnetBridge, networkId) + ) + ); + + vm.stopBroadcast(); + } +} diff --git a/vyper_contracts/bridgers/XLayerBridger.vy b/vyper_contracts/bridgers/XLayerBridger.vy new file mode 100644 index 0000000..648a2fa --- /dev/null +++ b/vyper_contracts/bridgers/XLayerBridger.vy @@ -0,0 +1,60 @@ +# @version 0.3.7 +""" +@title XLayer Bridge Wrapper +""" +from vyper.interfaces import ERC20 + +interface XLayerBridge: + def bridgeAsset(_destinationNetwork: uint32, _destinationAddress: address, _amount: uint256, _token: address, _forceUpdateGlobalExitRoot: bool, permitData: Bytes[128]): payable + +TOKEN: immutable(address) +XLAYER_BRIDGE: immutable(address) +# 1 = XLayer testnet +# 3 = XLayer mainnet +# see https://www.okx.com/xlayer/docs/developer/build-on-xlayer/bridge-to-xlayer +XLAYER_NETWORK_ID: immutable(uint32) + +is_approved: public(HashMap[address, bool]) + +@external +def __init__(_token: address, _xlayer_bridge: address, _xlayer_network_id: uint32): + TOKEN = _token + XLAYER_BRIDGE = _xlayer_bridge + XLAYER_NETWORK_ID = _xlayer_network_id + + assert ERC20(_token).approve(_xlayer_bridge, max_value(uint256), default_return_value=True) + self.is_approved[_token] = True + +@external +def bridge(_token: address, _to: address, _amount: uint256): + """ + @notice Bridge a token to XLayer mainnet using the L1 Standard Bridge + @param _token The token to bridge + @param _to The address to deposit the token to on L2 + @param _amount The amount of the token to deposit + """ + assert ERC20(_token).transferFrom(msg.sender, self, _amount, default_return_value=True) + if _token != TOKEN and not self.is_approved[_token]: + assert ERC20(_token).approve(XLAYER_BRIDGE, max_value(uint256), default_return_value=True) + self.is_approved[_token] = True + + XLayerBridge(XLAYER_BRIDGE).bridgeAsset(XLAYER_NETWORK_ID, _to, _amount, _token, True, b"") + + +@pure +@external +def cost() -> uint256: + """ + @notice Cost in OKB to bridge + """ + return 0 + + +@pure +@external +def check(_account: address) -> bool: + """ + @notice Check if `_account` may bridge via `transmit_emissions` + @param _account The account to check + """ + return True \ No newline at end of file