From 56f0b7ec35011420934d9076f19d4e536de8c978 Mon Sep 17 00:00:00 2001 From: Eliyahu Gusovsky Date: Thu, 16 Nov 2023 08:23:37 +0200 Subject: [PATCH] SpritzBridgeReceiver --- contracts/utility/SpritzBridgeReceiver.sol | 67 ++++++++++++++++++++++ src/abi/SpritzBridgeReceiver.json | 19 ++++++ tasks/deploy/index.ts | 1 + tasks/deploy/spritzBridgeReceiver.ts | 19 ++++++ 4 files changed, 106 insertions(+) create mode 100644 contracts/utility/SpritzBridgeReceiver.sol create mode 100644 src/abi/SpritzBridgeReceiver.json create mode 100644 tasks/deploy/spritzBridgeReceiver.ts diff --git a/contracts/utility/SpritzBridgeReceiver.sol b/contracts/utility/SpritzBridgeReceiver.sol new file mode 100644 index 0000000..679f546 --- /dev/null +++ b/contracts/utility/SpritzBridgeReceiver.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.7; + +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +/** + * @title SpritzBridgeReceiver + * @author Spritz Finance + * @notice A utility contract for handling bridged funds + */ +contract SpritzBridgeReceiver is AccessControlEnumerable { + using SafeERC20 for IERC20; + + // @dev Bot which has permission to call the bridge function + bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE"); + + // @dev Address of paraswap + address internal _target = 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57; + // @dev Address of paraswap allowance target + address internal _allowanceTarget = 0x216B4B4Ba9F3e719726886d34a177484278Bfcae; + // @dev Circle receiving address + address internal _circleReceiving = 0xb0E2D41a14494717f42Ffc6327F9D250b0ad32a8; + + constructor(address bridgeRole) { + _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); + _setupRole(BRIDGE_ROLE, msg.sender); + _setupRole(BRIDGE_ROLE, bridgeRole); + } + + /** + * @dev Bridge deposited tokens via Jumper + * @param fromToken Token to swap + * @param amount How much to swap + * @param toToken Target token + * @param swapData Data for paraswap call + */ + function swapToken( + address fromToken, + uint amount, + address toToken, + bytes calldata swapData + ) external payable onlyRole(BRIDGE_ROLE) { + require(amount <= IERC20(fromToken).balanceOf(address(this)), "Amount exceeds balance"); + IERC20(fromToken).safeApprove(_allowanceTarget, amount); + _target.call{ value: msg.value }(swapData); + IERC20(toToken).transfer(_circleReceiving, IERC20(toToken).balanceOf(address(this))); + } + + /** + * @dev Withdraw deposited tokens to the given address + * @param token Token to withdraw + * @param to Target address + */ + function sweep(IERC20 token, address to) external onlyRole(BRIDGE_ROLE) { + token.transfer(to, token.balanceOf(address(this))); + } + + /** + * @dev Withdraw ETH to the given address + * @param to Target address + */ + function nativeSweep(address to) external onlyRole(BRIDGE_ROLE) { + to.call{ value: address(this).balance }(""); + } +} diff --git a/src/abi/SpritzBridgeReceiver.json b/src/abi/SpritzBridgeReceiver.json new file mode 100644 index 0000000..0ff881f --- /dev/null +++ b/src/abi/SpritzBridgeReceiver.json @@ -0,0 +1,19 @@ +[ + "constructor(address)", + "event RoleAdminChanged(bytes32 indexed,bytes32 indexed,bytes32 indexed)", + "event RoleGranted(bytes32 indexed,address indexed,address indexed)", + "event RoleRevoked(bytes32 indexed,address indexed,address indexed)", + "function BRIDGE_ROLE() view returns (bytes32)", + "function DEFAULT_ADMIN_ROLE() view returns (bytes32)", + "function getRoleAdmin(bytes32) view returns (bytes32)", + "function getRoleMember(bytes32,uint256) view returns (address)", + "function getRoleMemberCount(bytes32) view returns (uint256)", + "function grantRole(bytes32,address)", + "function hasRole(bytes32,address) view returns (bool)", + "function nativeSweep(address)", + "function renounceRole(bytes32,address)", + "function revokeRole(bytes32,address)", + "function supportsInterface(bytes4) view returns (bool)", + "function swapToken(address,uint256,address,bytes) payable", + "function sweep(address,address)" +] diff --git a/tasks/deploy/index.ts b/tasks/deploy/index.ts index 4866360..8e95f0c 100644 --- a/tasks/deploy/index.ts +++ b/tasks/deploy/index.ts @@ -1,6 +1,7 @@ import "./protocol/contractFactory"; import "./smartPay"; import "./spritzBridge"; +import "./spritzBridgeReceiver"; import "./spritzBridgeV2"; import "./spritzPay"; import "./spritzPayV2"; diff --git a/tasks/deploy/spritzBridgeReceiver.ts b/tasks/deploy/spritzBridgeReceiver.ts new file mode 100644 index 0000000..107e017 --- /dev/null +++ b/tasks/deploy/spritzBridgeReceiver.ts @@ -0,0 +1,19 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { task } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; + +const BRIDGE_BOT = "0xAAAF0666A916bdf97710A8E44e42BA250490e5b8"; + +task("deploy:SpritzBridgeReceiver").setAction(async function (_taskArguments: TaskArguments, hre) { + const bridgeFactory = await hre.ethers.getContractFactory("SpritzBridgeReceiver"); + console.log("Deploying"); + const args: [string] = [BRIDGE_BOT]; + const bridge = await bridgeFactory.deploy(...args); + await bridge.deployTransaction.wait(10); + console.log(`Deployed to ${bridge.address} with tx: ${bridge.deployTransaction.hash}`); + await hre.run(`verify:verify`, { + address: bridge.address, + contract: "contracts/utility/SpritzBridgeReceiver.sol:SpritzBridgeReceiver", + constructorArguments: args, + }); +});