diff --git a/helix-contract/contracts/mapping-token/v2/Guard.sol b/helix-contract/contracts/mapping-token/v2/Guard.sol index e13cef6..1897df0 100644 --- a/helix-contract/contracts/mapping-token/v2/Guard.sol +++ b/helix-contract/contracts/mapping-token/v2/Guard.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity >=0.8.17; +pragma solidity >=0.8.10; import "@zeppelin-solidity/contracts/security/Pausable.sol"; import "@zeppelin-solidity/contracts/token/ERC20/IERC20.sol"; @@ -11,23 +11,24 @@ import "../interfaces/IWToken.sol"; contract Guard is GuardRegistry, Pausable { using SafeMath for uint256; - mapping(uint256 => bytes32) deposits; + mapping(uint256 => bytes32) depositors; uint256 public maxUnclaimableTime; - mapping(address => bool) depositors; + address public depositor; address public operator; - event TokenDeposit(address sender, uint256 id, uint256 timestamp, address token, address recipient, uint256 amount); + event TokenDeposit(uint256 id, address token, address recipient, uint256 amount); event TokenClaimed(uint256 id); - constructor(address[] memory _guards, uint256 _threshold, uint256 _maxUnclaimableTime) { + constructor(address[] memory _guards, uint256 _threshold, uint256 _maxUnclaimableTime, address _depositor) { maxUnclaimableTime = _maxUnclaimableTime; + depositor = _depositor; operator = msg.sender; initialize(_guards, _threshold); } modifier onlyDepositor() { - require(depositors[msg.sender] == true, "Guard: Invalid depositor"); + require(msg.sender == depositor, "Guard: Invalid depositor"); _; } @@ -49,10 +50,6 @@ contract Guard is GuardRegistry, Pausable { operator = newOperator; } - function setDepositor(address depositor, bool enable) external onlyOperator { - depositors[depositor] = enable; - } - function setMaxUnclaimableTime(uint256 _maxUnclaimableTime) external onlyOperator { maxUnclaimableTime = _maxUnclaimableTime; } @@ -70,12 +67,11 @@ contract Guard is GuardRegistry, Pausable { address recipient, uint256 amount ) public onlyDepositor whenNotPaused { - deposits[id] = hash(abi.encodePacked(msg.sender, block.timestamp, token, recipient, amount)); - emit TokenDeposit(msg.sender, id, block.timestamp, token, recipient, amount); + depositors[id] = hash(abi.encodePacked(block.timestamp, token, recipient, amount)); + emit TokenDeposit(id, token, recipient, amount); } function claimById( - address from, uint256 id, uint256 timestamp, address token, @@ -83,18 +79,18 @@ contract Guard is GuardRegistry, Pausable { uint256 amount, bool isNative ) internal { - require(hash(abi.encodePacked(from, timestamp, token, recipient, amount)) == deposits[id], "Guard: Invalid id to claim"); + require(hash(abi.encodePacked(timestamp, token, recipient, amount)) == depositors[id], "Guard: Invalid id to claim"); require(amount > 0, "Guard: Invalid amount to claim"); if (isNative) { - require(IERC20(token).transferFrom(from, address(this), amount), "Guard: claim native token failed"); + require(IERC20(token).transferFrom(depositor, address(this), amount), "Guard: claim native token failed"); 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); } else { - require(IERC20(token).transferFrom(from, recipient, amount), "Guard: claim token failed"); + require(IERC20(token).transferFrom(depositor, recipient, amount), "Guard: claim token failed"); } - delete deposits[id]; + delete depositors[id]; emit TokenClaimed(id); } @@ -104,7 +100,6 @@ contract Guard is GuardRegistry, Pausable { * @param signatures the signatures of the guards which to claim tokens. */ function claim( - address from, uint256 id, uint256 timestamp, address token, @@ -112,8 +107,8 @@ contract Guard is GuardRegistry, Pausable { uint256 amount, bytes[] memory signatures ) public { - verifyGuardSignaturesWithoutNonce(msg.sig, abi.encode(from, id, timestamp, token, recipient, amount), signatures); - claimById(from, id, timestamp, token, recipient, amount, false); + verifyGuardSignaturesWithoutNonce(msg.sig, abi.encode(id, timestamp, token, recipient, amount), signatures); + claimById(id, timestamp, token, recipient, amount, false); } /** @@ -122,7 +117,6 @@ contract Guard is GuardRegistry, Pausable { * @param signatures the signatures of the guards which to claim tokens. */ function claimNative( - address from, uint256 id, uint256 timestamp, address token, @@ -130,8 +124,8 @@ contract Guard is GuardRegistry, Pausable { uint256 amount, bytes[] memory signatures ) public { - verifyGuardSignaturesWithoutNonce(msg.sig, abi.encode(from, id, timestamp, token, recipient, amount), signatures); - claimById(from, id, timestamp, token, recipient, amount, true); + verifyGuardSignaturesWithoutNonce(msg.sig, abi.encode(id, timestamp, token, recipient, amount), signatures); + claimById(id, timestamp, token, recipient, amount, true); } /** @@ -139,7 +133,6 @@ contract Guard is GuardRegistry, Pausable { * @param id the id to be claimed */ function claimByTimeout( - address from, uint256 id, uint256 timestamp, address token, @@ -148,11 +141,10 @@ contract Guard is GuardRegistry, Pausable { bool isNative ) public whenNotPaused { require(timestamp < block.timestamp && block.timestamp - timestamp > maxUnclaimableTime, "Guard: claim at invalid time"); - claimById(from, id, timestamp, token, recipient, amount, isNative); + claimById(id, timestamp, token, recipient, amount, isNative); } function hash(bytes memory value) public pure returns (bytes32) { return sha256(value); } } - diff --git a/helix-contract/contracts/mapping-token/v3/base/xTokenIssuing.sol b/helix-contract/contracts/mapping-token/v3/base/xTokenIssuing.sol index 57c9db6..c0a024d 100644 --- a/helix-contract/contracts/mapping-token/v3/base/xTokenIssuing.sol +++ b/helix-contract/contracts/mapping-token/v3/base/xTokenIssuing.sol @@ -65,6 +65,8 @@ contract xTokenIssuing is xTokenBridgeBase { emit IssuingERC20Created(_originalChainId, _originalToken, xToken); } + // using this interface, the Issuing contract must be must be granted mint and burn authorities. + // warning: if the _xToken contract has no transferOwnership/acceptOwnership interface, then the authority cannot be transfered. function updatexToken( uint256 _originalChainId, address _originalToken, diff --git a/helix-contract/contracts/messagers/MsglineMessager.sol b/helix-contract/contracts/messagers/MsglineMessager.sol index 5457222..03dc5e3 100644 --- a/helix-contract/contracts/messagers/MsglineMessager.sol +++ b/helix-contract/contracts/messagers/MsglineMessager.sol @@ -105,6 +105,7 @@ contract MsglineMessager is Application, AccessController { emit CallResult(_srcAppChainId, transferId, success); } + // We need to assume that transferId is unpredictable function slashMessage(bytes32 _transferId) external { require(slashTransferIds[_transferId] == 0, "!slash"); uint256 expiredTimestamp = block.timestamp + SLASH_EXPIRE_TIME; diff --git a/helix-contract/test/6_test_xtoken_v3.js b/helix-contract/test/6_test_xtoken_v3.js index 9e88372..5e180f5 100644 --- a/helix-contract/test/6_test_xtoken_v3.js +++ b/helix-contract/test/6_test_xtoken_v3.js @@ -87,11 +87,11 @@ describe("xtoken tests", () => { return x.address.toLowerCase().localeCompare(y.address.toLowerCase()) }); - const guardBackingContract = await ethers.getContractFactory("Guard"); + const guardBackingContract = await ethers.getContractFactory("GuardV3"); const backingGuard = await guardBackingContract.deploy([guards[0].address, guards[1].address, guards[2].address], 2, 60); await backingGuard.deployed(); await backingGuard.setDepositor(backing.address, true); - const guardIssuingContract = await ethers.getContractFactory("Guard"); + const guardIssuingContract = await ethers.getContractFactory("GuardV3"); const issuingGuard = await guardIssuingContract.deploy([guards[0].address, guards[1].address, guards[2].address], 2, 60); await issuingGuard.deployed(); await issuingGuard.setDepositor(issuing.address, true);