Skip to content

Commit

Permalink
Merge pull request #53 from helix-bridge/xiaoch05-guard-transfer
Browse files Browse the repository at this point in the history
Transfer tokens in guard contract
  • Loading branch information
xiaoch05 authored Feb 20, 2024
2 parents 0c0a881 + 57a28c5 commit 8b15cf6
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 267 deletions.
19 changes: 13 additions & 6 deletions helix-contract/contracts/mapping-token/v3/GuardV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "@zeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "@zeppelin-solidity/contracts/utils/math/SafeMath.sol";
import "./GuardRegistryV3.sol";
import "../interfaces/IWToken.sol";
import "../../utils/TokenTransferHelper.sol";

contract GuardV3 is GuardRegistryV3, Pausable {
using SafeMath for uint256;
Expand All @@ -20,9 +21,14 @@ contract GuardV3 is GuardRegistryV3, Pausable {
event TokenDeposit(address sender, uint256 id, uint256 timestamp, address token, address recipient, uint256 amount);
event TokenClaimed(uint256 id);

constructor(address[] memory _guards, uint256 _threshold, uint256 _maxUnclaimableTime) {
constructor(
address[] memory _guards,
address _operator,
uint256 _threshold,
uint256 _maxUnclaimableTime
) {
maxUnclaimableTime = _maxUnclaimableTime;
operator = msg.sender;
operator = _operator;
initialize(_guards, _threshold);
}

Expand Down Expand Up @@ -53,7 +59,8 @@ contract GuardV3 is GuardRegistryV3, Pausable {
depositors[depositor] = enable;
}

function setMaxUnclaimableTime(uint256 _maxUnclaimableTime) external onlyOperator {
function setMaxUnclaimableTime(uint256 _maxUnclaimableTime, bytes[] memory signatures) external {
verifyGuardSignatures(msg.sig, abi.encode(_maxUnclaimableTime), signatures);
maxUnclaimableTime = _maxUnclaimableTime;
}

Expand Down Expand Up @@ -87,13 +94,13 @@ contract GuardV3 is GuardRegistryV3, Pausable {
require(amount > 0, "Guard: Invalid amount to claim");
delete deposits[id];
if (isNative) {
require(IERC20(token).transferFrom(from, address(this), amount), "Guard: claim native token failed");
TokenTransferHelper.safeTransferFrom(token, from, address(this), amount);
uint256 balanceBefore = address(this).balance;
IWToken(token).withdraw(amount);
require(address(this).balance == balanceBefore.add(amount), "Guard: token is not wrapped by native token");
payable(recipient).transfer(amount);
TokenTransferHelper.safeTransferNative(recipient, amount);
} else {
require(IERC20(token).transferFrom(from, recipient, amount), "Guard: claim token failed");
TokenTransferHelper.safeTransferFrom(token, from, recipient, amount);
}
emit TokenClaimed(id);
}
Expand Down
243 changes: 145 additions & 98 deletions helix-contract/flatten/xtoken-v3/GuardV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,144 @@
* '----------------' '----------------' '----------------' '----------------' '----------------' '
*
*
* 2/6/2024
* 2/20/2024
**/

pragma solidity ^0.8.17;

// File @zeppelin-solidity/contracts/token/ERC20/[email protected]
// License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)


/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);

/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);

/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);

/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);

/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);

/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);

/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);

/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}

// File contracts/utils/TokenTransferHelper.sol
// License-Identifier: MIT

library TokenTransferHelper {
function safeTransfer(
address token,
address receiver,
uint256 amount
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(
IERC20.transfer.selector,
receiver,
amount
));
require(success && (data.length == 0 || abi.decode(data, (bool))), "helix:transfer token failed");
}

function safeTransferFrom(
address token,
address sender,
address receiver,
uint256 amount
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(
IERC20.transferFrom.selector,
sender,
receiver,
amount
));
require(success && (data.length == 0 || abi.decode(data, (bool))), "helix:transferFrom token failed");
}

function safeTransferNative(
address receiver,
uint256 amount
) internal {
(bool success,) = payable(receiver).call{value: amount}("");
require(success, "helix:transfer native token failed");
}
}

// File contracts/mapping-token/interfaces/IWToken.sol
// License-Identifier: MIT


interface IWToken {
function deposit() external payable;
function withdraw(uint wad) external;
}

// File @zeppelin-solidity/contracts/utils/[email protected]
// License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
Expand Down Expand Up @@ -608,15 +741,6 @@ contract GuardRegistryV3 {
}
}

// File contracts/mapping-token/interfaces/IWToken.sol
// License-Identifier: MIT


interface IWToken {
function deposit() external payable;
function withdraw(uint wad) external;
}

// File @zeppelin-solidity/contracts/utils/[email protected]
// License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
Expand Down Expand Up @@ -746,89 +870,6 @@ abstract contract Pausable is Context {
}
}

// File @zeppelin-solidity/contracts/token/ERC20/[email protected]
// License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)


/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);

/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);

/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);

/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);

/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);

/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);

/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);

/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}

// File @zeppelin-solidity/contracts/utils/math/[email protected]
// License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)
Expand Down Expand Up @@ -1065,6 +1106,7 @@ library SafeMath {




contract GuardV3 is GuardRegistryV3, Pausable {
using SafeMath for uint256;

Expand All @@ -1077,9 +1119,14 @@ contract GuardV3 is GuardRegistryV3, Pausable {
event TokenDeposit(address sender, uint256 id, uint256 timestamp, address token, address recipient, uint256 amount);
event TokenClaimed(uint256 id);

constructor(address[] memory _guards, uint256 _threshold, uint256 _maxUnclaimableTime) {
constructor(
address[] memory _guards,
address _operator,
uint256 _threshold,
uint256 _maxUnclaimableTime
) {
maxUnclaimableTime = _maxUnclaimableTime;
operator = msg.sender;
operator = _operator;
initialize(_guards, _threshold);
}

Expand Down Expand Up @@ -1144,13 +1191,13 @@ contract GuardV3 is GuardRegistryV3, Pausable {
require(amount > 0, "Guard: Invalid amount to claim");
delete deposits[id];
if (isNative) {
require(IERC20(token).transferFrom(from, address(this), amount), "Guard: claim native token failed");
TokenTransferHelper.safeTransferFrom(token, from, address(this), amount);
uint256 balanceBefore = address(this).balance;
IWToken(token).withdraw(amount);
require(address(this).balance == balanceBefore.add(amount), "Guard: token is not wrapped by native token");
payable(recipient).transfer(amount);
TokenTransferHelper.safeTransferNative(recipient, amount);
} else {
require(IERC20(token).transferFrom(from, recipient, amount), "Guard: claim token failed");
TokenTransferHelper.safeTransferFrom(token, from, recipient, amount);
}
emit TokenClaimed(id);
}
Expand Down
8 changes: 6 additions & 2 deletions helix-contract/flatten/xtoken-v3/MsglineMessager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* '----------------' '----------------' '----------------' '----------------' '----------------' '
*
*
* 12/26/2023
* 1/30/2024
**/

pragma solidity ^0.8.17;
Expand Down Expand Up @@ -94,7 +94,7 @@ abstract contract Application {


contract MsglineMessager is Application, AccessController {
IMessageLine public immutable msgline;
IMessageLine public msgline;

struct RemoteMessager {
uint256 msglineRemoteChainId;
Expand Down Expand Up @@ -128,6 +128,10 @@ contract MsglineMessager is Application, AccessController {
msgline = IMessageLine(_msgline);
}

function setMsgline(address _msgline) onlyDao external {
msgline = IMessageLine(_msgline);
}

function setRemoteMessager(uint256 _appRemoteChainId, uint256 _msglineRemoteChainId, address _remoteMessager) onlyDao external {
remoteMessagers[_appRemoteChainId] = RemoteMessager(_msglineRemoteChainId, _remoteMessager);
}
Expand Down
Loading

0 comments on commit 8b15cf6

Please sign in to comment.