diff --git a/contracts/integration/LockboxAdapterBlast.sol b/contracts/integration/LockboxAdapterBlast.sol new file mode 100644 index 0000000..eac0f9e --- /dev/null +++ b/contracts/integration/LockboxAdapterBlast.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IXERC20} from "../shared/IXERC20/IXERC20.sol"; +import {IXERC20Lockbox} from "../shared/IXERC20/IXERC20Lockbox.sol"; + +interface IXERC20Registry { + function getXERC20(address erc20) external view returns (address xerc20); + + function getERC20(address xerc20) external view returns (address erc20); + + function getLockbox(address erc20) external view returns (address xerc20); +} + +interface L1StandardBridge { + function bridgeERC20To( + address _localToken, + address _remoteToken, + address _to, + uint256 _amount, + uint32 _minGasLimit, + bytes calldata _extraData + ) external; +} + +/// @notice This adapter is only used for sending assets from Ethereum mainnet to Blast. +/// @dev Combines Lockbox deposit and Blast bridge's BridgeERC20 call. +contract LockboxAdapterBlast { + address immutable blastStandardBridge; + address immutable registry; + + // ERRORS + error AmountLessThanZero(); + + constructor(address _blastStandardBridge, address _registry) { + blastStandardBridge = _blastStandardBridge; + registry = _registry; + } + + /// @dev Combines Lockbox deposit and Blast bridge's BridgeERC20To call. + /// @param _to The recipient or contract address on destination. + /// @param _erc20 The address of the adopted ERC20 on the origin chain. + /// @param _remoteToken The address of the asset to be received on the destination chain. + /// @param _amount The amount of asset to bridge. + /// @param _minGasLimit Minimum amount of gas that the bridge can be relayed with. + /// @param _extraData Extra data to be sent with the transaction. + function bridgeTo( + address _to, + address _erc20, + address _remoteToken, + uint256 _amount, + uint32 _minGasLimit, + bytes calldata _extraData + ) external { + if (_amount <= 0) { + revert AmountLessThanZero(); + } + + address xerc20 = IXERC20Registry(registry).getXERC20(_erc20); + address lockbox = IXERC20Registry(registry).getLockbox(xerc20); + + SafeERC20.safeTransferFrom(IERC20(_erc20), msg.sender, address(this), _amount); + IERC20(_erc20).approve(lockbox, _amount); + IXERC20Lockbox(lockbox).deposit(_amount); + IERC20(xerc20).approve(blastStandardBridge, _amount); + L1StandardBridge(blastStandardBridge).bridgeERC20To(xerc20, _remoteToken, _to, _amount, _minGasLimit, _extraData); + } +} diff --git a/script/DeployLockboxAdapterBlast.s.sol b/script/DeployLockboxAdapterBlast.s.sol new file mode 100644 index 0000000..76a34a9 --- /dev/null +++ b/script/DeployLockboxAdapterBlast.s.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Script.sol"; +import {LockboxAdapterBlast} from "../contracts/integration/LockboxAdapterBlast.sol"; + +contract DeployLockboxAdapterBlast is Script { + function run() public { + vm.startBroadcast(); + + new LockboxAdapterBlast( + address(0x697402166Fbf2F22E970df8a6486Ef171dbfc524), // blastStandardBridge + address(0xBf29A2D67eFb6766E44c163B19C6F4118b164702) // registry + ); + + vm.stopBroadcast(); + } +}