Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lockbox adapters #41

Merged
merged 3 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions contracts/integration/DappRadar/DappRadarLockboxAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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";
import {IXReceiver} from "@connext/interfaces/core/IXReceiver.sol";

contract DappRadarLockboxAdapter is IXReceiver {
IXERC20Lockbox public lockbox;
IERC20 public erc20;
IXERC20 public xerc20;

constructor(address _lockbox, address _erc20, address _xerc20) {
lockbox = IXERC20Lockbox(_lockbox);
erc20 = IERC20(_erc20);
xerc20 = IXERC20(_xerc20);
}

/// @notice Deposit ERC20s into the Lockbox
/// @param _amount Amount of ERC20s to use
/// @param _recipient Recipient of the xERC20s
function deposit(uint256 _amount, address _recipient) internal {
require(_amount > 0, "Zero amount");
IERC20 _xerc20 = IERC20(address(xerc20));

if (erc20.allowance(address(this), address(lockbox)) < _amount) {
erc20.approve(address(lockbox), type(uint256).max);
}
lockbox.deposit(_amount);

// Transfer the xERC20s to the recipient
SafeERC20.safeTransfer(_xerc20, _recipient, _amount);
}

/// @notice Withdraw ERC20s from the Lockbox
/// @param _amount Amount of xERC20s to use
/// @param _recipient Recipient of the ERC20s
function withdraw(uint256 _amount, address _recipient) internal {
require(_amount > 0, "Zero amount");
IERC20 _xerc20 = IERC20(address(xerc20));

if (_xerc20.allowance(address(this), address(lockbox)) < _amount) {
_xerc20.approve(address(lockbox), type(uint256).max);
}
lockbox.withdraw(_amount);

// Transfer the ERC20s to the recipient
SafeERC20.safeTransfer(erc20, _recipient, _amount);
}

/// @dev This function receives xERC20s from Connext and calls the Lockbox
/// @param _amount The amount of funds that will be received.
/// @param _asset The address of the asset that will be received.
/// @param _transferId The id of the transfer.
/// @param _callData The data that will be sent to the targets.
function xReceive(
bytes32 _transferId,
uint256 _amount,
address _asset,
address _originSender,
uint32 _origin,
bytes memory _callData
) external returns (bytes memory) {
// Check for the right xerc20
require(_asset == address(xerc20), "Wrong asset received");

// Unpack the _callData to get the recipient's address
address _recipient = abi.decode(_callData, (address));

withdraw(_amount, _recipient);
}
}
74 changes: 74 additions & 0 deletions contracts/integration/Grumpycat/GrumpycatLockboxAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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";
import {IXReceiver} from "@connext/interfaces/core/IXReceiver.sol";

contract GrumpycatLockboxAdapter is IXReceiver {
IXERC20Lockbox public lockbox;
IERC20 public erc20;
IXERC20 public xerc20;

constructor(address _lockbox, address _erc20, address _xerc20) {
lockbox = IXERC20Lockbox(_lockbox);
erc20 = IERC20(_erc20);
xerc20 = IXERC20(_xerc20);
}

/// @notice Deposit ERC20s into the Lockbox
/// @param _amount Amount of ERC20s to use
/// @param _recipient Recipient of the xERC20s
function deposit(uint256 _amount, address _recipient) internal {
require(_amount > 0, "Zero amount");
IERC20 _xerc20 = IERC20(address(xerc20));

if (erc20.allowance(address(this), address(lockbox)) < _amount) {
erc20.approve(address(lockbox), type(uint256).max);
}
lockbox.deposit(_amount);

// Transfer the xERC20s to the recipient
SafeERC20.safeTransfer(_xerc20, _recipient, _amount);
}

/// @notice Withdraw ERC20s from the Lockbox
/// @param _amount Amount of xERC20s to use
/// @param _recipient Recipient of the ERC20s
function withdraw(uint256 _amount, address _recipient) internal {
require(_amount > 0, "Zero amount");
IERC20 _xerc20 = IERC20(address(xerc20));

if (_xerc20.allowance(address(this), address(lockbox)) < _amount) {
_xerc20.approve(address(lockbox), type(uint256).max);
}
lockbox.withdraw(_amount);

// Transfer the ERC20s to the recipient
SafeERC20.safeTransfer(erc20, _recipient, _amount);
}

/// @dev This function receives xERC20s from Connext and calls the Lockbox
/// @param _amount The amount of funds that will be received.
/// @param _asset The address of the asset that will be received.
/// @param _transferId The id of the transfer.
/// @param _callData The data that will be sent to the targets.
function xReceive(
bytes32 _transferId,
uint256 _amount,
address _asset,
address _originSender,
uint32 _origin,
bytes memory _callData
) external returns (bytes memory) {
// Check for the right xerc20
require(_asset == address(xerc20), "Wrong asset received");

// Unpack the _callData to get the recipient's address
address _recipient = abi.decode(_callData, (address));

withdraw(_amount, _recipient);
}
}
115 changes: 115 additions & 0 deletions contracts/shared/IXERC20/IXERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.4 <0.9.0;

interface IXERC20 {
/**
* @notice Emits when a lockbox is set
*
* @param _lockbox The address of the lockbox
*/

event LockboxSet(address _lockbox);

/**
* @notice Emits when a limit is set
*
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limit too
*/
event BridgeLimitsSet(uint256 _mintingLimit, uint256 _burningLimit, address indexed _bridge);

/**
* @notice Reverts when a user with too low of a limit tries to call mint/burn
*/

error IXERC20_NotHighEnoughLimits();

/**
* @notice Reverts when caller is not the factory
*/

error IXERC20_NotFactory();

struct Bridge {
BridgeParameters minterParams;
BridgeParameters burnerParams;
}

struct BridgeParameters {
uint256 timestamp;
uint256 ratePerSecond;
uint256 maxLimit;
uint256 currentLimit;
}

/**
* @notice Sets the lockbox address
*
* @param _lockbox The address of the lockbox
*/

function setLockbox(address _lockbox) external;

/**
* @notice Updates the limits of any bridge
* @dev Can only be called by the owner
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limits too
*/
function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external;

/**
* @notice Returns the max limit of a minter
*
* @param _minter The minter we are viewing the limits of
* @return _limit The limit the minter has
*/
function mintingMaxLimitOf(address _minter) external view returns (uint256 _limit);

/**
* @notice Returns the max limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/

function burningMaxLimitOf(address _bridge) external view returns (uint256 _limit);

/**
* @notice Returns the current limit of a minter
*
* @param _minter The minter we are viewing the limits of
* @return _limit The limit the minter has
*/

function mintingCurrentLimitOf(address _minter) external view returns (uint256 _limit);

/**
* @notice Returns the current limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/

function burningCurrentLimitOf(address _bridge) external view returns (uint256 _limit);

/**
* @notice Mints tokens for a user
* @dev Can only be called by a minter
* @param _user The address of the user who needs tokens minted
* @param _amount The amount of tokens being minted
*/

function mint(address _user, uint256 _amount) external;

/**
* @notice Burns tokens for a user
* @dev Can only be called by a minter
* @param _user The address of the user who needs tokens burned
* @param _amount The amount of tokens being burned
*/

function burn(address _user, uint256 _amount) external;
}
50 changes: 50 additions & 0 deletions contracts/shared/IXERC20/IXERC20Lockbox.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.4 <0.9.0;

interface IXERC20Lockbox {
/**
* @notice Emitted when tokens are deposited into the lockbox
*/

event Deposit(address _sender, uint256 _amount);

/**
* @notice Emitted when tokens are withdrawn from the lockbox
*/

event Withdraw(address _sender, uint256 _amount);

/**
* @notice Reverts when a user tries to deposit native tokens on a non-native lockbox
*/

error IXERC20Lockbox_NotNative();

/**
* @notice Reverts when a user tries to deposit non-native tokens on a native lockbox
*/

error IXERC20Lockbox_Native();

/**
* @notice Reverts when a user tries to withdraw and the call fails
*/

error IXERC20Lockbox_WithdrawFailed();

/**
* @notice Deposit ERC20 tokens into the lockbox
*
* @param _amount The amount of tokens to deposit
*/

function deposit(uint256 _amount) external;

/**
* @notice Withdraw ERC20 tokens from the lockbox
*
* @param _amount The amount of tokens to withdraw
*/

function withdraw(uint256 _amount) external;
}
3 changes: 2 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ out = 'out'
libs = ['node_modules', 'lib']
test = 'test'
cache_path = 'cache_forge'
solc = "0.8.19"
solc = "0.8.19"
via_ir = true
15 changes: 15 additions & 0 deletions script/DappRadar/DeployDappRadarLockBoxAdapter.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import {DappRadarLockboxAdapter} from "../../contracts/integration/DappRadar/DappRadarLockboxAdapter.sol";

contract DeployDappRadarLockboxAdapter is Script {
function run(address lockbox, address erc20, address xerc20) external {
vm.startBroadcast();

new DappRadarLockboxAdapter(lockbox, erc20, xerc20);

vm.stopBroadcast();
}
}
15 changes: 15 additions & 0 deletions script/Grumpycat/DeployGrumpycatLockboxAdapter.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import {GrumpycatLockboxAdapter} from "../../contracts/integration/Grumpycat/GrumpycatLockboxAdapter.sol";

contract DeployGrumpycatLockboxAdapter is Script {
function run(address lockbox, address erc20, address xerc20) external {
vm.startBroadcast();

new GrumpycatLockboxAdapter(lockbox, erc20, xerc20);

vm.stopBroadcast();
}
}
Loading