From a8e93355bf94cd2fa055bdfce9e8a0cc0e8f9e18 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Thu, 25 Aug 2022 17:22:28 +0100 Subject: [PATCH 01/20] Add SafeTransfer to DepositBox --- .../mainnet/DepositBoxes/DepositBoxERC20.sol | 69 ++++++------------- 1 file changed, 21 insertions(+), 48 deletions(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 01a598a85..777662b38 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -25,7 +25,8 @@ import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/DoubleEndedQueueUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; -import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "@skalenetwork/ima-interfaces/mainnet/DepositBoxes/IDepositBoxERC20.sol"; import "../../Messages.sol"; @@ -47,6 +48,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { using AddressUpgradeable for address; using DoubleEndedQueueUpgradeable for DoubleEndedQueueUpgradeable.Bytes32Deque; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; + using SafeERC20Upgradeable for IERC20MetadataUpgradeable; enum DelayedTransferStatus { DELAYED, @@ -133,7 +135,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { address contractReceiver = schainLinks[schainHash]; require(contractReceiver != address(0), "Unconnected chain"); require( - ERC20Upgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount, + IERC20MetadataUpgradeable(erc20OnMainnet).allowance(msg.sender, address(this)) >= amount, "DepositBox was not approved for ERC20 token" ); bytes memory data = _receiveERC20( @@ -143,21 +145,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { amount ); _saveTransferredAmount(schainHash, erc20OnMainnet, amount); - if (erc20OnMainnet == _USDT_ADDRESS) { - // solhint-disable-next-line no-empty-blocks - try IERC20TransferVoid(erc20OnMainnet).transferFrom(msg.sender, address(this), amount) {} catch { - revert("Transfer was failed"); - } - } else { - require( - ERC20Upgradeable(erc20OnMainnet).transferFrom( - msg.sender, - address(this), - amount - ), - "Transfer was failed" - ); - } + IERC20MetadataUpgradeable(erc20OnMainnet).safeTransferFrom(msg.sender, address(this), amount); messageProxy.postOutgoingMessage( schainHash, contractReceiver, @@ -187,7 +175,10 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { { Messages.TransferErc20Message memory message = Messages.decodeTransferErc20Message(data); require(message.token.isContract(), "Given address is not a contract"); - require(ERC20Upgradeable(message.token).balanceOf(address(this)) >= message.amount, "Not enough money"); + require( + IERC20MetadataUpgradeable(message.token).balanceOf(address(this)) >= message.amount, + "Not enough money" + ); _removeTransferredAmount(schainHash, message.token, message.amount); uint256 delay = _delayConfig[schainHash].transferDelay; @@ -198,7 +189,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { ) { _createDelayedTransfer(schainHash, message, delay); } else { - _transfer(message.token, message.receiver, message.amount); + IERC20MetadataUpgradeable(message.token).safeTransfer(message.receiver, message.amount); } } @@ -241,10 +232,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bytes32 schainHash = _schainHash(schainName); require(transferredAmount[schainHash][erc20OnMainnet] >= amount, "Incorrect amount"); _removeTransferredAmount(schainHash, erc20OnMainnet, amount); - require( - ERC20Upgradeable(erc20OnMainnet).transfer(receiver, amount), - "Transfer was failed" - ); + IERC20MetadataUpgradeable(erc20OnMainnet).safeTransfer(receiver, amount); } /** @@ -405,7 +393,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { require(transfer.status == DelayedTransferStatus.ARBITRAGE, "Arbitrage has to be active"); transfer.status = DelayedTransferStatus.COMPLETED; delete transfer.untilTimestamp; - _transfer(transfer.token, transfer.receiver, transfer.amount); + IERC20MetadataUpgradeable(transfer.token).safeTransfer(transfer.receiver, transfer.amount); } /** @@ -428,7 +416,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { transfer.status = DelayedTransferStatus.COMPLETED; delete transfer.untilTimestamp; // msg.sender is schain owner - _transfer(transfer.token, msg.sender, transfer.amount); + IERC20MetadataUpgradeable(transfer.token).safeTransfer(msg.sender, transfer.amount); } /** @@ -616,7 +604,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { delayedTransfers[transferId].status = DelayedTransferStatus.COMPLETED; } retrieved = true; - _transfer(transfer.token, transfer.receiver, transfer.amount); + IERC20MetadataUpgradeable(transfer.token).safeTransfer(transfer.receiver, transfer.amount); } } else { // status is COMPLETED @@ -687,7 +675,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { returns (bytes memory data) { bytes32 schainHash = _schainHash(schainName); - ERC20Upgradeable erc20 = ERC20Upgradeable(erc20OnMainnet); + IERC20MetadataUpgradeable erc20 = IERC20MetadataUpgradeable(erc20OnMainnet); uint256 totalSupply = erc20.totalSupply(); require(amount <= totalSupply, "Amount is incorrect"); bool isERC20AddedToSchain = _schainToERC20[schainHash].contains(erc20OnMainnet); @@ -769,25 +757,6 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { } } - /** - * @dev Transfer ERC20 token or USDT - */ - function _transfer(address token, address receiver, uint256 amount) private { - // there is no other reliable way to determine USDT - // slither-disable-next-line incorrect-equality - if (token == _USDT_ADDRESS) { - // solhint-disable-next-line no-empty-blocks - try IERC20TransferVoid(token).transfer(receiver, amount) {} catch { - revert("Transfer was failed"); - } - } else { - require( - ERC20Upgradeable(token).transfer(receiver, amount), - "Transfer was failed" - ); - } - } - /** * Create instance of DelayedTransfer and initialize all auxiliary fields. */ @@ -825,14 +794,18 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Returns total supply of ERC20 token. */ - function _getErc20TotalSupply(ERC20Upgradeable erc20Token) private view returns (uint256) { + function _getErc20TotalSupply(IERC20MetadataUpgradeable erc20Token) private view returns (uint256) { return erc20Token.totalSupply(); } /** * @dev Returns info about ERC20 token such as token name, decimals, symbol. */ - function _getErc20TokenInfo(ERC20Upgradeable erc20Token) private view returns (Messages.Erc20TokenInfo memory) { + function _getErc20TokenInfo(IERC20MetadataUpgradeable erc20Token) + private + view + returns (Messages.Erc20TokenInfo memory) + { return Messages.Erc20TokenInfo({ name: erc20Token.name(), decimals: erc20Token.decimals(), From 8cff93471af167ed0a23b7d64e27508c3af2e31d Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Thu, 25 Aug 2022 17:26:00 +0100 Subject: [PATCH 02/20] Remove USDT constant --- proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 777662b38..64a27cbfd 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -73,7 +73,6 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { uint256 arbitrageDuration; } - address private constant _USDT_ADDRESS = 0xdAC17F958D2ee523a2206206994597C13D831ec7; uint256 private constant _QUEUE_PROCESSING_LIMIT = 10; bytes32 public constant ARBITER_ROLE = keccak256("ARBITER_ROLE"); From d7cccc5ae3097b32978988173ba0b249e565df2f Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Fri, 26 Aug 2022 22:34:16 +0100 Subject: [PATCH 03/20] Add tests --- .../contracts/test/ERC20IncorrectTransfer.sol | 25 ++++ .../test/ERC20TransferWithFalseReturn.sol | 25 ++++ .../test/ERC20TransferWithoutReturn.sol | 24 +++ proxy/contracts/test/ERC20WithoutTransfer.sol | 139 ++++++++++++++++++ proxy/test/DepositBoxERC20.ts | 100 +++++++++++++ 5 files changed, 313 insertions(+) create mode 100644 proxy/contracts/test/ERC20IncorrectTransfer.sol create mode 100644 proxy/contracts/test/ERC20TransferWithFalseReturn.sol create mode 100644 proxy/contracts/test/ERC20TransferWithoutReturn.sol create mode 100644 proxy/contracts/test/ERC20WithoutTransfer.sol diff --git a/proxy/contracts/test/ERC20IncorrectTransfer.sol b/proxy/contracts/test/ERC20IncorrectTransfer.sol new file mode 100644 index 000000000..2e1fe4b7d --- /dev/null +++ b/proxy/contracts/test/ERC20IncorrectTransfer.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity 0.8.16; + +import "./ERC20WithoutTransfer.sol"; + +interface IERC20IncorrectTransfer is IERC20WithoutTransfer { + function transferFrom(address sender, address recipient, uint256 amount, bytes memory) external; +} + + +contract ERC20IncorrectTransfer is IERC20IncorrectTransfer, ERC20WithoutTransfer { + + // solhint-disable-next-line no-empty-blocks + constructor(string memory tokenName, string memory tokenSymbol) ERC20WithoutTransfer(tokenName, tokenSymbol) {} + + function transferFrom(address sender, address recipient, uint256 amount, bytes memory) public override { + _transfer(sender, recipient, amount); + _approve( + sender, + msg.sender, + allowance(sender, msg.sender) - amount + ); + } +} diff --git a/proxy/contracts/test/ERC20TransferWithFalseReturn.sol b/proxy/contracts/test/ERC20TransferWithFalseReturn.sol new file mode 100644 index 000000000..1dc3779fc --- /dev/null +++ b/proxy/contracts/test/ERC20TransferWithFalseReturn.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity 0.8.16; + +import "./ERC20WithoutTransfer.sol"; + +interface IERC20TransferWithFalseReturn is IERC20WithoutTransfer { + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); +} + +contract ERC20TransferWithFalseReturn is IERC20TransferWithFalseReturn, ERC20WithoutTransfer { + + // solhint-disable-next-line no-empty-blocks + constructor(string memory tokenName, string memory tokenSymbol) ERC20WithoutTransfer(tokenName, tokenSymbol) {} + + function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) { + _transfer(sender, recipient, amount); + _approve( + sender, + msg.sender, + allowance(sender, msg.sender) - amount + ); + return false; + } +} diff --git a/proxy/contracts/test/ERC20TransferWithoutReturn.sol b/proxy/contracts/test/ERC20TransferWithoutReturn.sol new file mode 100644 index 000000000..4ef8fe0ee --- /dev/null +++ b/proxy/contracts/test/ERC20TransferWithoutReturn.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity 0.8.16; + +import "./ERC20WithoutTransfer.sol"; + +interface IERC20TransferWithoutReturn is IERC20WithoutTransfer { + function transferFrom(address sender, address recipient, uint256 amount) external; +} + +contract ERC20TransferWithoutReturn is IERC20TransferWithoutReturn, ERC20WithoutTransfer { + + // solhint-disable-next-line no-empty-blocks + constructor(string memory tokenName, string memory tokenSymbol) ERC20WithoutTransfer(tokenName, tokenSymbol) {} + + function transferFrom(address sender, address recipient, uint256 amount) public override { + _transfer(sender, recipient, amount); + _approve( + sender, + msg.sender, + allowance(sender, msg.sender) - amount + ); + } +} diff --git a/proxy/contracts/test/ERC20WithoutTransfer.sol b/proxy/contracts/test/ERC20WithoutTransfer.sol new file mode 100644 index 000000000..746fbaa00 --- /dev/null +++ b/proxy/contracts/test/ERC20WithoutTransfer.sol @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +pragma solidity 0.8.16; + +interface IERC20WithoutTransfer { + function mint(address account, uint256 amount) external returns (bool); + function burn(uint256 amount) external; + function transfer(address recipient, uint256 amount) external returns (bool); + function approve(address spender, uint256 amount) external returns (bool); + function increaseAllowance(address spender, uint256 addedValue) external returns (bool); + function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); + function name() external view returns (string memory); + function decimals() external view returns (uint8); + function symbol() external view returns (string memory); + function totalSupply() external view returns (uint256); + function balanceOf(address account) external view returns (uint256); + function allowance(address owner, address spender) external view returns (uint256); +} + +abstract contract ERC20WithoutTransfer is IERC20WithoutTransfer { + + mapping (address => uint256) private _balances; + + mapping (address => mapping (address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + uint8 private _decimals; + + event Approval(address owner, address spender, uint256 amount); + + event Transfer(address from, address to, uint256 amount); + + constructor(string memory tokenName, string memory tokenSymbol) { + _name = tokenName; + _symbol = tokenSymbol; + _decimals = 18; + } + + function mint(address account, uint256 amount) external override returns (bool) { + _mint(account, amount); + return true; + } + + /** + * @dev burn - destroys token on msg sender + * + * NEED TO HAVE THIS FUNCTION ON SKALE-CHAIN + * + * @param amount - amount of tokens + */ + function burn(uint256 amount) external override { + _burn(msg.sender, amount); + } + + function transfer(address recipient, uint256 amount) public override returns (bool) { + _transfer(msg.sender, recipient, amount); + return true; + } + + function approve(address spender, uint256 amount) public override returns (bool) { + _approve(msg.sender, spender, amount); + return true; + } + + + function increaseAllowance(address spender, uint256 addedValue) public override returns (bool) { + _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue); + return true; + } + + function decreaseAllowance(address spender, uint256 subtractedValue) public override returns (bool) { + _approve( + msg.sender, + spender, + _allowances[msg.sender][spender] - subtractedValue + ); + return true; + } + + function name() public view override returns (string memory) { + return _name; + } + + function symbol() public view override returns (string memory) { + return _symbol; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } + + function totalSupply() public view override returns (uint256) { + return _totalSupply; + } + + function balanceOf(address account) public view override returns (uint256) { + return _balances[account]; + } + + function allowance(address owner, address spender) public view override returns (uint256) { + return _allowances[owner][spender]; + } + + function _transfer(address sender, address recipient, uint256 amount) internal virtual { + require(sender != address(0), "ERC20: transfer from the zero address"); + require(recipient != address(0), "ERC20: transfer to the zero address"); + + _balances[sender] = _balances[sender] - amount; + _balances[recipient] = _balances[recipient] + amount; + emit Transfer(sender, recipient, amount); + } + + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _totalSupply = _totalSupply + amount; + _balances[account] = _balances[account] + amount; + emit Transfer(address(0), account, amount); + } + + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _balances[account] = _balances[account] - amount; + _totalSupply = _totalSupply - amount; + emit Transfer(account, address(0), amount); + } + + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } +} diff --git a/proxy/test/DepositBoxERC20.ts b/proxy/test/DepositBoxERC20.ts index c946af4ac..d69c75d30 100644 --- a/proxy/test/DepositBoxERC20.ts +++ b/proxy/test/DepositBoxERC20.ts @@ -233,6 +233,39 @@ describe("DepositBoxERC20", () => { await depositBoxERC20.connect(schainOwner).addERC20TokenByOwner(schainName, erc20.address) .should.be.eventually.rejectedWith("Schain is killed"); }); + + it("should invoke `depositERC20` for non standard ERC20", async () => { + // preparation + // mint some quantity of ERC20 tokens for `deployer` address + const erc20TWR = await (await ethers.getContractFactory("ERC20TransferWithoutReturn")).deploy("Test", "TST"); + const erc20TWFR = await (await ethers.getContractFactory("ERC20TransferWithFalseReturn")).deploy("Test", "TST"); + const erc20IT = await (await ethers.getContractFactory("ERC20IncorrectTransfer")).deploy("Test", "TST"); + const amount = 10; + await erc20TWR.connect(deployer).mint(deployer.address, amount); + await erc20TWFR.connect(deployer).mint(deployer.address, amount); + await erc20IT.connect(deployer).mint(deployer.address, amount); + await erc20.connect(deployer).mint(deployer.address, amount); + await erc20TWR.connect(deployer).approve(depositBoxERC20.address, amount); + await erc20TWFR.connect(deployer).approve(depositBoxERC20.address, amount); + await erc20IT.connect(deployer).approve(depositBoxERC20.address, amount); + await erc20.connect(deployer).approve(depositBoxERC20.address, amount); + // execution + await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName); + await depositBoxERC20 + .connect(deployer) + .depositERC20(schainName, erc20.address, 1); + await depositBoxERC20 + .connect(deployer) + .depositERC20(schainName, erc20TWR.address, 1); + await depositBoxERC20 + .connect(deployer) + .depositERC20(schainName, erc20IT.address, 1) + .should.be.eventually.rejectedWith("SafeERC20: low-level call failed"); + await depositBoxERC20 + .connect(deployer) + .depositERC20(schainName, erc20TWFR.address, 1) + .should.be.eventually.rejectedWith("SafeERC20: ERC20 operation did not succeed"); + }); }); describe("tests for `postMessage` function", async () => { @@ -330,6 +363,73 @@ describe("DepositBoxERC20", () => { }); + it("should transfer non standard ERC20 token", async () => { + // preparation + const erc20TWR = await (await ethers.getContractFactory("ERC20TransferWithoutReturn")).deploy("Test", "TST"); + const amount = 10; + const to = user.address; + const senderFromSchain = deployer.address; + const wei = 1e18.toString(); + + const sign = { + blsSignature: BlsSignature, + counter: Counter, + hashA: HashA, + hashB: HashB, + }; + + const message = { + data: await messages.encodeTransferErc20Message(erc20.address, to, amount), + destinationContract: depositBoxERC20.address, + sender: senderFromSchain + }; + const messageTWR = { + data: await messages.encodeTransferErc20Message(erc20TWR.address, to, amount), + destinationContract: depositBoxERC20.address, + sender: senderFromSchain + }; + + await initializeSchain(contractManager, schainName, schainOwner.address, 1, 1); + await setCommonPublicKey(contractManager, schainName); + + await depositBoxERC20.connect(user).depositERC20(schainName, erc20.address, amount) + .should.be.eventually.rejectedWith("Unconnected chain"); + + await linker + .connect(deployer) + .connectSchain(schainName, [deployer.address, deployer.address, deployer.address]); + + await communityPool + .connect(user) + .rechargeUserWallet(schainName, user.address, { value: wei }); + + await depositBoxERC20.connect(schainOwner).disableWhitelist(schainName); + await erc20.connect(deployer).mint(user.address, amount * 2); + await erc20TWR.connect(deployer).mint(user.address, amount * 2); + + await erc20.connect(user).approve(depositBoxERC20.address, amount * 2); + await erc20TWR.connect(user).approve(depositBoxERC20.address, amount * 2); + + await depositBoxERC20.connect(user).depositERC20(schainName, erc20.address, amount); + await depositBoxERC20.connect(user).depositERC20(schainName, erc20TWR.address, amount); + + const balanceBefore = await deployer.getBalance(); + await messageProxy.connect(nodeAddress).postIncomingMessages(schainName, 0, [message, messageTWR], sign); + const balance = await deployer.getBalance(); + balance.should.be.least(balanceBefore); + balance.should.be.closeTo(balanceBefore, 10); + + await depositBoxERC20.connect(user).depositERC20(schainName, erc20.address, amount); + await depositBoxERC20.connect(user).depositERC20(schainName, erc20TWR.address, amount); + await messageProxy.connect(nodeAddress).postIncomingMessages(schainName, 2, [message, messageTWR], sign); + expect(BigNumber.from(await depositBoxERC20.transferredAmount(schainHash, erc20.address)).toString()).to.be.equal(BigNumber.from(0).toString()); + expect(BigNumber.from(await depositBoxERC20.transferredAmount(schainHash, erc20TWR.address)).toString()).to.be.equal(BigNumber.from(0).toString()); + + (await erc20.balanceOf(user.address)).toString().should.be.equal((amount * 2).toString()); + (await erc20TWR.balanceOf(user.address)).toString().should.be.equal((amount * 2).toString()); + + }); + describe("When user deposited tokens", async () => { let token: ERC20OnChain; let token2: ERC20OnChain; From b51def461be73d84f3043127b778a5774041c80e Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 20 Oct 2022 16:26:39 +0300 Subject: [PATCH 04/20] Fix the bug --- .../mainnet/DepositBoxes/DepositBoxERC20.sol | 81 ++++++++++--------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 64a27cbfd..1b5862de5 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -70,7 +70,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { mapping(address => uint256) bigTransferThreshold; EnumerableSetUpgradeable.AddressSet trustedReceivers; uint256 transferDelay; - uint256 arbitrageDuration; + uint256 arbitrageDuration; } uint256 private constant _QUEUE_PROCESSING_LIMIT = 10; @@ -86,19 +86,19 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { // exits delay configuration // schainHash => delay config - mapping(bytes32 => DelayConfig) private _delayConfig; + mapping(bytes32 => DelayConfig) private _delayConfig; uint256 public delayedTransfersSize; // delayed transfer id => delayed transfer mapping(uint256 => DelayedTransfer) public delayedTransfers; // receiver address => delayed transfers ids queue - mapping(address => DoubleEndedQueueUpgradeable.Bytes32Deque) public delayedTransfersByReceiver; + mapping(address => DoubleEndedQueueUpgradeable.Bytes32Deque) public delayedTransfersByReceiver; /** * @dev Emitted when token is mapped in DepositBoxERC20. */ event ERC20TokenAdded(string schainName, address indexed contractOnMainnet); - + /** * @dev Emitted when token is received by DepositBox and is ready to be cloned * or transferred on SKALE chain. @@ -111,9 +111,9 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Allows `msg.sender` to send ERC20 token from mainnet to schain - * + * * Requirements: - * + * * - Schain name must not be `Mainnet`. * - Receiver account on schain cannot be null. * - Schain that receives tokens should not be killed. @@ -154,9 +154,9 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Allows MessageProxyForMainnet contract to execute transferring ERC20 token from schain to mainnet. - * + * * Requirements: - * + * * - Schain from which the tokens came should not be killed. * - Sender contract should be defined and schain name cannot be `Mainnet`. * - Amount of tokens on DepositBoxERC20 should be equal or more than transferred amount. @@ -186,7 +186,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { && _delayConfig[schainHash].bigTransferThreshold[message.token] <= message.amount && !isReceiverTrusted(schainHash, message.receiver) ) { - _createDelayedTransfer(schainHash, message, delay); + _createDelayedTransfer(schainHash, message, delay); } else { IERC20MetadataUpgradeable(message.token).safeTransfer(message.receiver, message.amount); } @@ -194,11 +194,11 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Allows Schain owner to add an ERC20 token to DepositBoxERC20. - * + * * Emits an {ERC20TokenAdded} event. - * + * * Requirements: - * + * * - Schain should not be killed. * - Only owner of the schain able to run function. */ @@ -213,11 +213,11 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Allows Schain owner to return each user their tokens. - * The Schain owner decides which tokens to send to which address, + * The Schain owner decides which tokens to send to which address, * since the contract on mainnet does not store information about which tokens belong to whom. * * Requirements: - * + * * - Amount of tokens on schain should be equal or more than transferred amount. * - msg.sender should be an owner of schain * - IMA transfers Mainnet <-> schain should be killed @@ -241,7 +241,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * and can be canceled by a voting * * Requirements: - * + * * - msg.sender should be an owner of schain */ function setBigTransferValue( @@ -254,7 +254,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { onlySchainOwner(schainName) { bytes32 schainHash = _schainHash(schainName); - _delayConfig[schainHash].bigTransferThreshold[token] = value; + _delayConfig[schainHash].bigTransferThreshold[token] = value; } /** @@ -264,7 +264,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * and can be canceled by a voting * * Requirements: - * + * * - msg.sender should be an owner of schain */ function setBigTransferDelay( @@ -278,7 +278,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bytes32 schainHash = _schainHash(schainName); // need to restrict big delays to avoid overflow require(delayInSeconds < 1e8, "Delay is too big"); // no more then ~ 3 years - _delayConfig[schainHash].transferDelay = delayInSeconds; + _delayConfig[schainHash].transferDelay = delayInSeconds; } /** @@ -286,7 +286,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * After escalation the transfer is locked for provided period of time. * * Requirements: - * + * * - msg.sender should be an owner of schain */ function setArbitrageDuration( @@ -300,13 +300,13 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bytes32 schainHash = _schainHash(schainName); // need to restrict big delays to avoid overflow require(delayInSeconds < 1e8, "Delay is too big"); // no more then ~ 3 years - _delayConfig[schainHash].arbitrageDuration = delayInSeconds; + _delayConfig[schainHash].arbitrageDuration = delayInSeconds; } /** * @dev Add the address to a whitelist of addresses that can do big transfers without delaying * Requirements: - * + * * - msg.sender should be an owner of schain * - the address must not be in the whitelist */ @@ -321,13 +321,13 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { require( _delayConfig[_schainHash(schainName)].trustedReceivers.add(receiver), "Receiver already is trusted" - ); + ); } /** * @dev Remove the address from a whitelist of addresses that can do big transfers without delaying * Requirements: - * + * * - msg.sender should be an owner of schain * - the address must be in the whitelist */ @@ -354,7 +354,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * @dev Initialize arbitrage of a suspicious big transfer * * Requirements: - * + * * - msg.sender should be an owner of schain or have ARBITER_ROLE role * - transfer must be delayed and arbitrage must not be started */ @@ -377,7 +377,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * @dev Approve a big transfer and immidiately transfer tokens during arbitrage * * Requirements: - * + * * - msg.sender should be an owner of schain * - arbitrage of the transfer must be started */ @@ -399,7 +399,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * @dev Reject a big transfer and transfer tokens to SKALE chain owner during arbitrage * * Requirements: - * + * * - msg.sender should be an owner of schain * - arbitrage of the transfer must be started */ @@ -441,7 +441,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { } /** - * @dev Should return true if token was added by Schain owner or + * @dev Should return true if token was added by Schain owner or * added automatically after sending to schain if whitelist was turned off. */ function getSchainToERC20( @@ -457,7 +457,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { } /** - * @dev Should return length of a set of all mapped tokens which were added by Schain owner + * @dev Should return length of a set of all mapped tokens which were added by Schain owner * or added automatically after sending to schain if whitelist was turned off. */ function getSchainToAllERC20Length(string calldata schainName) external view override returns (uint256) { @@ -465,7 +465,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { } /** - * @dev Should return an array of range of tokens were added by Schain owner + * @dev Should return an array of range of tokens were added by Schain owner * or added automatically after sending to schain if whitelist was turned off. */ function getSchainToAllERC20( @@ -580,7 +580,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bool retrieved = false; for (uint256 i = 0; i < transfersAmount; ++i) { uint256 transferId = uint256(delayedTransfersByReceiver[receiver].at(currentIndex)); - DelayedTransfer memory transfer = delayedTransfers[transferId]; + DelayedTransfer memory transfer = delayedTransfers[transferId]; ++currentIndex; if (transfer.status != DelayedTransferStatus.COMPLETED) { @@ -609,6 +609,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { // status is COMPLETED if (currentIndex == 1) { --currentIndex; + retrieved = true; _removeOldestDelayedTransfer(receiver); } } @@ -656,11 +657,11 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Allows DepositBoxERC20 to receive ERC20 tokens. - * + * * Emits an {ERC20TokenReady} event. - * + * * Requirements: - * + * * - Amount must be less than or equal to the total supply of the ERC20 contract. * - Whitelist should be turned off for auto adding tokens to DepositBoxERC20. */ @@ -701,11 +702,11 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { /** * @dev Adds an ERC20 token to DepositBoxERC20. - * + * * Emits an {ERC20TokenAdded} event. - * + * * Requirements: - * + * * - Given address should be contract. */ function _addERC20ForSchain(string calldata schainName, address erc20OnMainnet) private { @@ -736,9 +737,9 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * the element is added at back - depthLimit index */ function _addToDelayedQueueWithPriority( - DoubleEndedQueueUpgradeable.Bytes32Deque storage queue, - uint256 id, - uint256 until, + DoubleEndedQueueUpgradeable.Bytes32Deque storage queue, + uint256 id, + uint256 until, uint256 depthLimit ) private @@ -785,7 +786,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { function _removeOldestDelayedTransfer(address receiver) private { uint256 transferId = uint256(delayedTransfersByReceiver[receiver].popFront()); // For most cases the loop will have only 1 iteration. - // In worst case the amount of iterations is limited by _QUEUE_PROCESSING_LIMIT + // In worst case the amount of iterations is limited by _QUEUE_PROCESSING_LIMIT // slither-disable-next-line costly-loop delete delayedTransfers[transferId]; } From 9222c83bb9204d3ccae6fa035bbcd830d0a23a41 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 25 Oct 2022 17:06:19 +0300 Subject: [PATCH 05/20] Add test --- proxy/test/DepositBoxERC20.ts | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/proxy/test/DepositBoxERC20.ts b/proxy/test/DepositBoxERC20.ts index d69c75d30..2c038f7ef 100644 --- a/proxy/test/DepositBoxERC20.ts +++ b/proxy/test/DepositBoxERC20.ts @@ -62,6 +62,7 @@ import { BigNumber, Wallet } from "ethers"; import { assert, expect, use } from "chai"; import { createNode } from "./utils/skale-manager-utils/nodes"; import { currentTime, skipTime } from "./utils/time"; +import { join } from "path"; const BlsSignature: [BigNumber, BigNumber] = [ BigNumber.from("178325537405109593276798394634841698946852714038246117383766698579865918287"), @@ -612,6 +613,58 @@ describe("DepositBoxERC20", () => { .should.be.equal(token1BalanceBefore.add(2 * amount + 3 * bigAmount)); }); + it("should not stuck after big amount of competed transfers", async () => { + const bigTransfer = { + data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount), + destinationContract: depositBoxERC20.address, + sender: deployer.address + }; + + const token1BalanceBefore = await token.balanceOf(user.address); + const amountOfCompetedTransfers = 15; + + // send `amountOfCompetedTransfers` + 1 big transfer + const batch = (await messageProxy.MESSAGES_LENGTH()).toNumber(); + const fullBatches = Math.floor((amountOfCompetedTransfers + 1) / batch); + const rest = amountOfCompetedTransfers + 1 - fullBatches * batch; + for (let i = 0; i < fullBatches; ++i) { + await messageProxy.connect(nodeAddress).postIncomingMessages( + schainName, + i * batch, + Array(batch).fill(bigTransfer), + randomSignature + ); + } + if (rest > 0) { + await messageProxy.connect(nodeAddress).postIncomingMessages( + schainName, + fullBatches * batch, + Array(rest).fill(bigTransfer), + randomSignature + ); + } + + (await token.balanceOf(user.address)).should.be.equal(token1BalanceBefore); + + for (const completedTransfer of [...Array(amountOfCompetedTransfers).keys()]) { + await depositBoxERC20.escalate(completedTransfer); + await depositBoxERC20.connect(schainOwner).validateTransfer(completedTransfer); + } + + (await token.balanceOf(user.address)).should.be.equal(token1BalanceBefore.add(bigAmount * amountOfCompetedTransfers)); + + await skipTime(timeDelay); + + // first retrieve removes already completed transfers after an arbitrage from the queue + await depositBoxERC20.retrieveFor(user.address); + (await token.balanceOf(user.address)).should.be.equal(token1BalanceBefore.add(bigAmount * amountOfCompetedTransfers)); + + // second retrieve withdraws the rest + await depositBoxERC20.retrieveFor(user.address); + (await token.balanceOf(user.address)).should.be.equal(token1BalanceBefore.add(bigAmount * (amountOfCompetedTransfers + 1))); + + }); + it("should not allow to set too big delays", async () => { const tenYears = Math.round(60 * 60 * 24 * 365.25 * 10) From eace03f6883a5eb87cff37917db1c70582f7729b Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 24 Oct 2022 17:29:22 +0300 Subject: [PATCH 06/20] Skip failed transfers --- .../mainnet/DepositBoxes/DepositBoxERC20.sol | 19 ++++++++++++++++++- proxy/package.json | 2 +- proxy/yarn.lock | 8 ++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index 1b5862de5..ae2c1fa44 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -49,6 +49,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { using DoubleEndedQueueUpgradeable for DoubleEndedQueueUpgradeable.Bytes32Deque; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; using SafeERC20Upgradeable for IERC20MetadataUpgradeable; + using SafeERC20Upgradeable for IERC20Upgradeable; enum DelayedTransferStatus { DELAYED, @@ -109,6 +110,11 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { event Escalated(uint256 id); + /** + * @dev Emitted when token transfer is skipped due to internal token error + */ + event TransferSkipped(uint256 id); + /** * @dev Allows `msg.sender` to send ERC20 token from mainnet to schain * @@ -418,6 +424,11 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { IERC20MetadataUpgradeable(transfer.token).safeTransfer(msg.sender, transfer.amount); } + function doTransfer(address token, address receiver, uint256 amount) external override { + require(msg.sender == address(this), "Internal use only"); + IERC20Upgradeable(token).safeTransfer(receiver, amount); + } + /** * @dev Returns receiver of message. * @@ -603,7 +614,13 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { delayedTransfers[transferId].status = DelayedTransferStatus.COMPLETED; } retrieved = true; - IERC20MetadataUpgradeable(transfer.token).safeTransfer(transfer.receiver, transfer.amount); + try + this.doTransfer(transfer.token, transfer.receiver, transfer.amount) + // solhint-disable-next-line no-empty-blocks + {} + catch { + emit TransferSkipped(transferId); + } } } else { // status is COMPLETED diff --git a/proxy/package.json b/proxy/package.json index 7763c2dd5..37a01e933 100644 --- a/proxy/package.json +++ b/proxy/package.json @@ -26,7 +26,7 @@ "@openzeppelin/contracts-upgradeable": "^4.7.1", "@openzeppelin/hardhat-upgrades": "^1.9.0", "@skalenetwork/etherbase-interfaces": "^0.0.1-develop.20", - "@skalenetwork/ima-interfaces": "1.0.0-develop.20", + "@skalenetwork/ima-interfaces": "^1.0.0-withdrawals-blocking.1", "@skalenetwork/skale-manager-interfaces": "1.0.0-develop.1", "axios": "^0.21.4", "dotenv": "^10.0.0", diff --git a/proxy/yarn.lock b/proxy/yarn.lock index c722628ae..e82a8e181 100644 --- a/proxy/yarn.lock +++ b/proxy/yarn.lock @@ -757,10 +757,10 @@ resolved "https://registry.yarnpkg.com/@skalenetwork/etherbase-interfaces/-/etherbase-interfaces-0.0.1-develop.20.tgz#33f61e18d695fd47063aa39dce4df335d26b9528" integrity sha512-j3xnuQtOtjvjAoUMJgSUFxRa9/Egkg1RyA8r6PjcEb33VksE4LWLBy0PNFUFehLZv48595JROTcViGeXXwg5HQ== -"@skalenetwork/ima-interfaces@1.0.0-develop.20": - version "1.0.0-develop.20" - resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-develop.20.tgz#e4ae92f9832c08d289690f080b22363fa8f3a339" - integrity sha512-OV6lHSg/UiezfLHM/STawOlu2P0IxAXXVL0LilyunuOAtSg3lLfRRyTJKD3D+JePfhgIc25B8DUxJiRyQg4UIg== +"@skalenetwork/ima-interfaces@^1.0.0-withdrawals-blocking.1": + version "1.0.0-withdrawals-blocking.1" + resolved "https://registry.yarnpkg.com/@skalenetwork/ima-interfaces/-/ima-interfaces-1.0.0-withdrawals-blocking.1.tgz#f973c63a74fa0bca3ee72a967d7e2aa80680fa4a" + integrity sha512-pETNThx9NDGdmbdUVXmrf58Fw883SglWak1cmo+FIhKzDrQm+cTxZhX9xdrBoWy2WDmNk37ZmseMx0v454ozCg== dependencies: "@skalenetwork/skale-manager-interfaces" "^0.1.2" From 7319130ae3108b282e16acf84702d9a78d1159dc Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 27 Oct 2022 17:22:11 +0300 Subject: [PATCH 07/20] Add a test --- .../{ => erc20}/ERC20IncorrectTransfer.sol | 0 .../ERC20TransferWithFalseReturn.sol | 0 .../ERC20TransferWithoutReturn.sol | 0 .../test/{ => erc20}/ERC20WithoutTransfer.sol | 0 .../contracts/test/erc20/RevertableERC20.sol | 62 +++++++++++++++++++ proxy/test/DepositBoxERC20.ts | 36 +++++++++++ 6 files changed, 98 insertions(+) rename proxy/contracts/test/{ => erc20}/ERC20IncorrectTransfer.sol (100%) rename proxy/contracts/test/{ => erc20}/ERC20TransferWithFalseReturn.sol (100%) rename proxy/contracts/test/{ => erc20}/ERC20TransferWithoutReturn.sol (100%) rename proxy/contracts/test/{ => erc20}/ERC20WithoutTransfer.sol (100%) create mode 100644 proxy/contracts/test/erc20/RevertableERC20.sol diff --git a/proxy/contracts/test/ERC20IncorrectTransfer.sol b/proxy/contracts/test/erc20/ERC20IncorrectTransfer.sol similarity index 100% rename from proxy/contracts/test/ERC20IncorrectTransfer.sol rename to proxy/contracts/test/erc20/ERC20IncorrectTransfer.sol diff --git a/proxy/contracts/test/ERC20TransferWithFalseReturn.sol b/proxy/contracts/test/erc20/ERC20TransferWithFalseReturn.sol similarity index 100% rename from proxy/contracts/test/ERC20TransferWithFalseReturn.sol rename to proxy/contracts/test/erc20/ERC20TransferWithFalseReturn.sol diff --git a/proxy/contracts/test/ERC20TransferWithoutReturn.sol b/proxy/contracts/test/erc20/ERC20TransferWithoutReturn.sol similarity index 100% rename from proxy/contracts/test/ERC20TransferWithoutReturn.sol rename to proxy/contracts/test/erc20/ERC20TransferWithoutReturn.sol diff --git a/proxy/contracts/test/ERC20WithoutTransfer.sol b/proxy/contracts/test/erc20/ERC20WithoutTransfer.sol similarity index 100% rename from proxy/contracts/test/ERC20WithoutTransfer.sol rename to proxy/contracts/test/erc20/ERC20WithoutTransfer.sol diff --git a/proxy/contracts/test/erc20/RevertableERC20.sol b/proxy/contracts/test/erc20/RevertableERC20.sol new file mode 100644 index 000000000..beb3f94b8 --- /dev/null +++ b/proxy/contracts/test/erc20/RevertableERC20.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +/** + * RevertableERC20.sol - SKALE Interchain Messaging Agent + * Copyright (C) 2022-Present SKALE Labs + * @author Dmytro Stebaiev + * + * SKALE IMA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SKALE IMA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with SKALE IMA. If not, see . + */ + +pragma solidity 0.8.16; + +import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; + +interface IRevertableERC20 { + function enable() external; + function disable() external; + function mint(address account, uint amount) external; +} + +contract RevertableERC20 is IRevertableERC20, ERC20Upgradeable { + bool public enabled = true; + + constructor(string memory name, string memory symbol) initializer { + super.__ERC20_init(name, symbol); + } + + function enable() external override { + enabled = true; + } + + function disable() external override { + enabled = false; + } + + function mint(address account, uint amount) external override { + _mint(account, amount); + } + + function _transfer( + address from, + address to, + uint256 amount + ) + internal + override + { + require(enabled, "Transfers are disabled"); + super._transfer(from, to, amount); + } +} \ No newline at end of file diff --git a/proxy/test/DepositBoxERC20.ts b/proxy/test/DepositBoxERC20.ts index 2c038f7ef..d8242f2c9 100644 --- a/proxy/test/DepositBoxERC20.ts +++ b/proxy/test/DepositBoxERC20.ts @@ -665,6 +665,42 @@ describe("DepositBoxERC20", () => { }); + it("should not stuck if a token reverts transfer", async () => { + const bigTransfer = { + data: await messages.encodeTransferErc20Message(token.address, user.address, bigAmount), + destinationContract: depositBoxERC20.address, + sender: deployer.address + }; + + const badToken = await (await ethers.getContractFactory("RevertableERC20")).deploy("Test", "TST"); + await badToken.mint(user.address, bigAmount); + await badToken.connect(user).approve(depositBoxERC20.address, bigAmount); + await depositBoxERC20.connect(user).depositERC20(schainName, badToken.address, bigAmount); + + const badTokenBigTransfer = { + data: await messages.encodeTransferErc20Message(badToken.address, user.address, bigAmount), + destinationContract: depositBoxERC20.address, + sender: deployer.address + }; + + await messageProxy.connect(nodeAddress).postIncomingMessages( + schainName, + 0, + [ badTokenBigTransfer, bigTransfer ], + randomSignature + ); + + await skipTime(timeDelay); + + await badToken.disable(); + const balanceBefore = await token.balanceOf(user.address); + await expect( + depositBoxERC20.retrieveFor(user.address) + ).to.emit(depositBoxERC20, "TransferSkipped") + .withArgs(0); + (await token.balanceOf(user.address)).should.be.equal(balanceBefore.add(bigAmount)); + }); + it("should not allow to set too big delays", async () => { const tenYears = Math.round(60 * 60 * 24 * 365.25 * 10) From dbf9ed1e5a2582a157706bd4a671b1f155fb16ec Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 20 Oct 2022 16:48:03 +0300 Subject: [PATCH 08/20] Add events --- .../mainnet/MessageProxyForMainnet.sol | 78 +++++++++++-------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/proxy/contracts/mainnet/MessageProxyForMainnet.sol b/proxy/contracts/mainnet/MessageProxyForMainnet.sol index 56bf1aa04..0c9d8a257 100644 --- a/proxy/contracts/mainnet/MessageProxyForMainnet.sol +++ b/proxy/contracts/mainnet/MessageProxyForMainnet.sol @@ -37,7 +37,7 @@ import "./CommunityPool.sol"; /** * @title Message Proxy for Mainnet * @dev Runs on Mainnet, contains functions to manage the incoming messages from - * `targetSchainName` and outgoing messages to `fromSchainName`. Every SKALE chain with + * `targetSchainName` and outgoing messages to `fromSchainName`. Every SKALE chain with * IMA is therefore connected to MessageProxyForMainnet. * * Messages from SKALE chains are signed using BLS threshold signatures from the @@ -100,6 +100,20 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro uint256 newValue ); + /** + * @dev Emitted when the schain is paused + */ + event SchainPaused( + bytes32 schainHash + ); + + /** + * @dev Emitted when the schain is resumed + */ + event SchainResumed( + bytes32 schainHash + ); + /** * @dev Reentrancy guard for postIncomingMessages. */ @@ -117,9 +131,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Allows `msg.sender` to connect schain with MessageProxyOnMainnet for transferring messages. - * + * * Requirements: - * + * * - Schain name must not be `Mainnet`. */ function addConnectedChain(string calldata schainName) external override { @@ -132,9 +146,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Allows owner of the contract to set CommunityPool address for gas reimbursement. - * + * * Requirements: - * + * * - `msg.sender` must be granted as DEFAULT_ADMIN_ROLE. * - Address of CommunityPool contract must not be null. */ @@ -146,9 +160,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Allows `msg.sender` to register extra contract for being able to transfer messages from custom contracts. - * + * * Requirements: - * + * * - `msg.sender` must be granted as EXTRA_CONTRACT_REGISTRAR_ROLE. * - Schain name must not be `Mainnet`. */ @@ -159,16 +173,16 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro isSchainOwner(msg.sender, schainHash), "Not enough permissions to register extra contract" ); - require(schainHash != MAINNET_HASH, "Schain hash can not be equal Mainnet"); + require(schainHash != MAINNET_HASH, "Schain hash can not be equal Mainnet"); _registerExtraContract(schainHash, extraContract); } /** * @dev Allows `msg.sender` to remove extra contract, * thus `extraContract` will no longer be available to transfer messages from mainnet to schain. - * + * * Requirements: - * + * * - `msg.sender` must be granted as EXTRA_CONTRACT_REGISTRAR_ROLE. * - Schain name must not be `Mainnet`. */ @@ -184,10 +198,10 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro } /** - * @dev Posts incoming message from `fromSchainName`. - * + * @dev Posts incoming message from `fromSchainName`. + * * Requirements: - * + * * - `msg.sender` must be authorized caller. * - `fromSchainName` must be initialized. * - `startingCounter` must be equal to the chain's incoming message counter. @@ -218,7 +232,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro fromSchainName, _hashedArray(messages, startingCounter, fromSchainName), sign), "Signature is not verified"); - uint additionalGasPerMessage = + uint additionalGasPerMessage = (gasTotal - gasleft() + headerMessageGasCost + messages.length * messageGasCost) / messages.length; uint notReimbursedGas = 0; connectedChains[fromSchainHash].incomingMessageCounter += messages.length; @@ -243,9 +257,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Sets headerMessageGasCost to a new value. - * + * * Requirements: - * + * * - `msg.sender` must be granted as CONSTANT_SETTER_ROLE. */ function setNewHeaderMessageGasCost(uint256 newHeaderMessageGasCost) external override onlyConstantSetter { @@ -255,9 +269,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Sets messageGasCost to a new value. - * + * * Requirements: - * + * * - `msg.sender` must be granted as CONSTANT_SETTER_ROLE. */ function setNewMessageGasCost(uint256 newMessageGasCost) external override onlyConstantSetter { @@ -267,9 +281,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Sets new version of contracts on mainnet - * + * * Requirements: - * + * * - `msg.sender` must be granted DEFAULT_ADMIN_ROLE. */ function setVersion(string calldata newVersion) external override { @@ -282,9 +296,9 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro * @dev Allows PAUSABLE_ROLE to pause IMA bridge unlimited * or DEFAULT_ADMIN_ROLE to pause for 4 hours * or schain owner to pause unlimited after DEFAULT_ADMIN_ROLE pause it - * + * * Requirements: - * + * * - IMA bridge to current schain was not paused * - Sender should be PAUSABLE_ROLE, DEFAULT_ADMIN_ROLE or schain owner */ @@ -293,13 +307,14 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro require(hasRole(PAUSABLE_ROLE, msg.sender), "Incorrect sender"); require(!pauseInfo[schainHash].paused, "Already paused"); pauseInfo[schainHash].paused = true; + emit SchainPaused(schainHash); } /** - * @dev Allows DEFAULT_ADMIN_ROLE or schain owner to resume IMA bridge - * + * @dev Allows DEFAULT_ADMIN_ROLE or schain owner to resume IMA bridge + * * Requirements: - * + * * - IMA bridge to current schain was paused * - Sender should be DEFAULT_ADMIN_ROLE or schain owner */ @@ -308,6 +323,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || isSchainOwner(msg.sender, schainHash), "Incorrect sender"); require(pauseInfo[schainHash].paused, "Already unpaused"); pauseInfo[schainHash].paused = false; + emit SchainResumed(schainHash); } /** @@ -337,12 +353,12 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro /** * @dev Checks whether chain is currently connected. - * - * Note: Mainnet chain does not have a public key, and is implicitly + * + * Note: Mainnet chain does not have a public key, and is implicitly * connected to MessageProxy. - * + * * Requirements: - * + * * - `schainName` must not be Mainnet. */ function isConnectedChain( @@ -372,7 +388,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro || isContractRegistered(targetChainHash, msg.sender) || isSchainOwner(msg.sender, targetChainHash), "Sender contract is not registered" - ); + ); } /** @@ -402,7 +418,7 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro } /** - * @dev Checks whether balance of schain wallet is sufficient for + * @dev Checks whether balance of schain wallet is sufficient for * for reimbursement custom message. */ function _checkSchainBalance(bytes32 schainHash) internal view returns (bool) { From a0b01f01a080aeb7c3d6a4569050d0fa4cf395ba Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 28 Oct 2022 17:15:10 +0300 Subject: [PATCH 09/20] Make events fields indexed --- proxy/contracts/mainnet/MessageProxyForMainnet.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/contracts/mainnet/MessageProxyForMainnet.sol b/proxy/contracts/mainnet/MessageProxyForMainnet.sol index 0c9d8a257..1e9f05f90 100644 --- a/proxy/contracts/mainnet/MessageProxyForMainnet.sol +++ b/proxy/contracts/mainnet/MessageProxyForMainnet.sol @@ -104,14 +104,14 @@ contract MessageProxyForMainnet is SkaleManagerClient, MessageProxy, IMessagePro * @dev Emitted when the schain is paused */ event SchainPaused( - bytes32 schainHash + bytes32 indexed schainHash ); /** * @dev Emitted when the schain is resumed */ event SchainResumed( - bytes32 schainHash + bytes32 indexed schainHash ); /** From 4c0cefa2c148492cf59dca5f99b5cc1af0a3baf5 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 28 Oct 2022 17:18:36 +0300 Subject: [PATCH 10/20] Update a test --- proxy/test/MessageProxy.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/proxy/test/MessageProxy.ts b/proxy/test/MessageProxy.ts index 56958e4b4..0937901a6 100644 --- a/proxy/test/MessageProxy.ts +++ b/proxy/test/MessageProxy.ts @@ -265,7 +265,10 @@ describe("MessageProxy", () => { const pauseableRole = await messageProxyForMainnet.PAUSABLE_ROLE(); await messageProxyForMainnet.connect(deployer).grantRole(pauseableRole, client.address); - await messageProxyForMainnet.connect(client).pause(schainName); + await expect( + messageProxyForMainnet.connect(client).pause(schainName) + ).to.emit(messageProxyForMainnet, "SchainPaused") + .withArgs(schainHash); await messageProxyForMainnet.connect(client).pause(schainName).should.be.rejectedWith("Already paused"); (await messageProxyForMainnet.isPaused(schainHash)).should.be.deep.equal(true); @@ -278,7 +281,10 @@ describe("MessageProxy", () => { .should.be.rejectedWith("IMA is paused"); await messageProxyForMainnet.connect(client).resume(schainName).should.be.rejectedWith("Incorrect sender"); - await messageProxyForMainnet.connect(schainOwner).resume(schainName); + await expect( + messageProxyForMainnet.connect(schainOwner).resume(schainName) + ).to.emit(messageProxyForMainnet, "SchainResumed") + .withArgs(schainHash); await messageProxyForMainnet.connect(deployer).resume(schainName).should.be.rejectedWith("Already unpaused"); (await messageProxyForMainnet.isPaused(schainHash)).should.be.deep.equal(false); From 766f23a6fbbd4ebf7568ad923e55e5a79c95b91c Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 20 Oct 2022 17:02:27 +0300 Subject: [PATCH 11/20] Add events --- .../mainnet/DepositBoxes/DepositBoxERC20.sol | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index ae2c1fa44..f64e467d0 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -115,6 +115,34 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { */ event TransferSkipped(uint256 id); + /** + * @dev Emitted when big transfer threshold is changed + */ + event BigTransferThresholdIsChanged( + bytes32 schainHash, + address token, + uint256 oldValue, + uint256 newValue + ); + + /** + * @dev Emitted when big transfer delay is changed + */ + event BigTransferDelayIsChanged( + bytes32 schainHash, + uint256 oldValue, + uint256 newValue + ); + + /** + * @dev Emitted when arbitrage duration is changed + */ + event ArbitrageDurationIsChanged( + bytes32 schainHash, + uint256 oldValue, + uint256 newValue + ); + /** * @dev Allows `msg.sender` to send ERC20 token from mainnet to schain * @@ -260,6 +288,12 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { onlySchainOwner(schainName) { bytes32 schainHash = _schainHash(schainName); + emit BigTransferThresholdIsChanged( + schainHash, + token, + _delayConfig[schainHash].bigTransferThreshold[token], + value + ); _delayConfig[schainHash].bigTransferThreshold[token] = value; } @@ -284,6 +318,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bytes32 schainHash = _schainHash(schainName); // need to restrict big delays to avoid overflow require(delayInSeconds < 1e8, "Delay is too big"); // no more then ~ 3 years + emit BigTransferDelayIsChanged(schainHash, _delayConfig[schainHash].transferDelay, delayInSeconds); _delayConfig[schainHash].transferDelay = delayInSeconds; } @@ -306,6 +341,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { bytes32 schainHash = _schainHash(schainName); // need to restrict big delays to avoid overflow require(delayInSeconds < 1e8, "Delay is too big"); // no more then ~ 3 years + emit ArbitrageDurationIsChanged(schainHash, _delayConfig[schainHash].arbitrageDuration, delayInSeconds); _delayConfig[schainHash].arbitrageDuration = delayInSeconds; } From c9a4f9a6a14493bfde8307ffbc11cc0db28ef9cf Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 28 Oct 2022 17:28:40 +0300 Subject: [PATCH 12/20] Make events fields indexed --- proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index f64e467d0..f01254a34 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -119,7 +119,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * @dev Emitted when big transfer threshold is changed */ event BigTransferThresholdIsChanged( - bytes32 schainHash, + bytes32 indexed schainHash, address token, uint256 oldValue, uint256 newValue @@ -129,7 +129,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * @dev Emitted when big transfer delay is changed */ event BigTransferDelayIsChanged( - bytes32 schainHash, + bytes32 indexed schainHash, uint256 oldValue, uint256 newValue ); @@ -138,7 +138,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { * @dev Emitted when arbitrage duration is changed */ event ArbitrageDurationIsChanged( - bytes32 schainHash, + bytes32 indexed schainHash, uint256 oldValue, uint256 newValue ); From 06d03494e37fa7eda10f092de77c8d7ee980d837 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 28 Oct 2022 17:42:35 +0300 Subject: [PATCH 13/20] Update tests --- proxy/test/DepositBoxERC20.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/proxy/test/DepositBoxERC20.ts b/proxy/test/DepositBoxERC20.ts index d8242f2c9..6b37c51ad 100644 --- a/proxy/test/DepositBoxERC20.ts +++ b/proxy/test/DepositBoxERC20.ts @@ -471,10 +471,19 @@ describe("DepositBoxERC20", () => { await token2.connect(user).approve(depositBoxERC20.address, depositedAmount); await depositBoxERC20.connect(user).depositERC20(schainName, token2.address, depositedAmount); - await depositBoxERC20.connect(schainOwner).setBigTransferValue(schainName, token.address, bigAmount); + await expect( + depositBoxERC20.connect(schainOwner).setBigTransferValue(schainName, token.address, bigAmount) + ).to.emit(depositBoxERC20, "BigTransferThresholdIsChanged") + .withArgs(schainHash, token.address, 0, bigAmount); await depositBoxERC20.connect(schainOwner).setBigTransferValue(schainName, token2.address, bigAmount); - await depositBoxERC20.connect(schainOwner).setBigTransferDelay(schainName, timeDelay); - await depositBoxERC20.connect(schainOwner).setArbitrageDuration(schainName, arbitrageDuration); + await expect( + depositBoxERC20.connect(schainOwner).setBigTransferDelay(schainName, timeDelay) + ).to.emit(depositBoxERC20, "BigTransferDelayIsChanged") + .withArgs(schainHash, 0, timeDelay); + await expect( + depositBoxERC20.connect(schainOwner).setArbitrageDuration(schainName, arbitrageDuration) + ).to.emit(depositBoxERC20, "ArbitrageDurationIsChanged") + .withArgs(schainHash, 0, arbitrageDuration); await depositBoxERC20.grantRole(await depositBoxERC20.ARBITER_ROLE(), deployer.address); }); From 12b497f817130a99af3891a7853570fc76bf76c9 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Mon, 31 Oct 2022 12:20:52 +0200 Subject: [PATCH 14/20] Make token argument indexed --- proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol index f01254a34..4f25abadf 100644 --- a/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol +++ b/proxy/contracts/mainnet/DepositBoxes/DepositBoxERC20.sol @@ -120,7 +120,7 @@ contract DepositBoxERC20 is DepositBox, IDepositBoxERC20 { */ event BigTransferThresholdIsChanged( bytes32 indexed schainHash, - address token, + address indexed token, uint256 oldValue, uint256 newValue ); From b85d8e2e15d024ecc55e0ec8ee2e76f037c0af6b Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Tue, 8 Nov 2022 17:53:33 +0200 Subject: [PATCH 15/20] Add Goerli support --- proxy/migrations/tools/gnosis-safe.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/proxy/migrations/tools/gnosis-safe.ts b/proxy/migrations/tools/gnosis-safe.ts index b4938e319..6ea2c1937 100644 --- a/proxy/migrations/tools/gnosis-safe.ts +++ b/proxy/migrations/tools/gnosis-safe.ts @@ -9,6 +9,7 @@ type Ethers = typeof ethers & HardhatEthersHelpers; enum Network { MAINNET = 1, RINKEBY = 4, + GOERLI = 5, GANACHE = 1337, HARDHAT = 31337, } @@ -19,6 +20,7 @@ const ADDRESSES = { multiSend: { [Network.MAINNET]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", [Network.RINKEBY]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", + [Network.GOERLI]: "0x8D29bE29923b68abfDD21e541b9374737B49cdAD", }, } @@ -26,10 +28,12 @@ const URLS = { safe_transaction: { [Network.MAINNET]: "https://safe-transaction.mainnet.gnosis.io", [Network.RINKEBY]: "https://safe-transaction.rinkeby.gnosis.io", + [Network.GOERLI]: "https://safe-transaction.goerli.gnosis.io", }, safe_relay: { [Network.MAINNET]: "https://safe-relay.mainnet.gnosis.io", [Network.RINKEBY]: "https://safe-relay.rinkeby.gnosis.io", + [Network.GOERLI]: "https://safe-relay.goerli.gnosis.io", } } @@ -40,6 +44,8 @@ function getMultiSendAddress(chainId: number, isSafeMock: boolean = false) { return ADDRESSES.multiSend[chainId]; } else if (chainId === Network.RINKEBY) { return ADDRESSES.multiSend[chainId]; + } else if (chainId === Network.GOERLI) { + return ADDRESSES.multiSend[chainId]; } else if ([Network.GANACHE, Network.HARDHAT].includes(chainId)) { return ethers.constants.AddressZero; } else { @@ -50,7 +56,9 @@ function getMultiSendAddress(chainId: number, isSafeMock: boolean = false) { export function getSafeTransactionUrl(chainId: number) { if (chainId === Network.MAINNET) { return URLS.safe_transaction[chainId]; - } else if (chainId === 4) { + } else if (chainId === Network.RINKEBY) { + return URLS.safe_transaction[chainId]; + } else if (chainId === Network.GOERLI) { return URLS.safe_transaction[chainId]; } else { throw Error("Can't get safe-transaction url at network with chainId = " + chainId); From 5aaef7114ec19cb10e618eef091cb6baca26b95f Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 9 Nov 2022 16:05:30 +0200 Subject: [PATCH 16/20] Fix bug in verification script --- proxy/migrations/tools/verification.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/migrations/tools/verification.ts b/proxy/migrations/tools/verification.ts index bc37440ff..6373c6741 100644 --- a/proxy/migrations/tools/verification.ts +++ b/proxy/migrations/tools/verification.ts @@ -12,7 +12,7 @@ export async function verify(contractName: string, contractAddress: string, cons }); break; } catch (e: any) { - if (e.toString().includes("Already Verified")) { + if (e.toString().includes("Contract source code already verified")) { console.log(chalk.grey(`${contractName} is already verified`)); return; } From cbdbd7bc78badb0b4fa82cefa1398feb86c604b7 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Wed, 9 Nov 2022 16:48:36 +0200 Subject: [PATCH 17/20] Fix safe relay --- proxy/migrations/tools/gnosis-safe.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/proxy/migrations/tools/gnosis-safe.ts b/proxy/migrations/tools/gnosis-safe.ts index 6ea2c1937..1e5013f79 100644 --- a/proxy/migrations/tools/gnosis-safe.ts +++ b/proxy/migrations/tools/gnosis-safe.ts @@ -66,10 +66,8 @@ export function getSafeTransactionUrl(chainId: number) { } export function getSafeRelayUrl(chainId: number) { - if (chainId === 1) { - return URLS.safe_relay[chainId]; - } else if (chainId === 4) { - return URLS.safe_relay[chainId]; + if (Object.keys(URLS.safe_relay).includes(chainId.toString())) { + return URLS.safe_relay[chainId as keyof typeof URLS.safe_relay]; } else { throw Error("Can't get safe-relay url at network with chainId = " + chainId); } From 93377536f7cdfef35a21a76da40624ed14ed7868 Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Thu, 1 Dec 2022 19:41:05 +0200 Subject: [PATCH 18/20] Update deployed version --- proxy/DEPLOYED | 2 +- proxy/migrations/upgradeMainnet.ts | 69 +----------------------------- 2 files changed, 3 insertions(+), 68 deletions(-) diff --git a/proxy/DEPLOYED b/proxy/DEPLOYED index a939f53a1..8c9698aaf 100644 --- a/proxy/DEPLOYED +++ b/proxy/DEPLOYED @@ -1 +1 @@ -1.3.2-stable.1 \ No newline at end of file +1.3.4 \ No newline at end of file diff --git a/proxy/migrations/upgradeMainnet.ts b/proxy/migrations/upgradeMainnet.ts index 1cdb09380..3ca1967c1 100644 --- a/proxy/migrations/upgradeMainnet.ts +++ b/proxy/migrations/upgradeMainnet.ts @@ -9,75 +9,10 @@ import hre from "hardhat"; async function main() { await upgrade( - "1.3.2", + "1.3.4", contracts, async (safeTransactions, abi) => undefined, - async (safeTransactions, abi) => { - const proxyAdmin = await getManifestAdmin(hre); - const owner = await proxyAdmin.owner(); - const communityPoolName = "CommunityPool"; - const communityPoolFactory = await ethers.getContractFactory(communityPoolName); - const communityPoolAddress = abi[getContractKeyInAbiFile(communityPoolName) + "_address"]; - let communityPool; - if (communityPoolAddress) { - communityPool = communityPoolFactory.attach(communityPoolAddress) as CommunityPool; - const constantSetterRole = await communityPool.CONSTANT_SETTER_ROLE(); - const isHasRole = await communityPool.hasRole(constantSetterRole, owner); - if (!isHasRole) { - console.log(chalk.yellow("Prepare transaction to grantRole CONSTANT_SETTER_ROLE to " + owner)); - safeTransactions.push(encodeTransaction( - 0, - communityPoolAddress, - 0, - communityPool.interface.encodeFunctionData("grantRole", [constantSetterRole, owner]) - )); - } - console.log(chalk.yellow("Prepare transaction to set multiplier to 3/2")); - safeTransactions.push(encodeTransaction( - 0, - communityPoolAddress, - 0, - communityPool.interface.encodeFunctionData("setMultiplier", [3, 2]) - )); - console.log(chalk.yellow("Prepare transaction to set header message gas cost to 73800")); - } else { - console.log(chalk.red("CommunityPool was not found!")); - console.log(chalk.red("Check your abi!!!")); - process.exit(1); - } - - const messageProxyForMainnet = (await ethers.getContractFactory("MessageProxyForMainnet")) - .attach(abi[getContractKeyInAbiFile("MessageProxyForMainnet") + "_address"]) as MessageProxyForMainnet; - - if (! await messageProxyForMainnet.hasRole(await messageProxyForMainnet.CONSTANT_SETTER_ROLE(), owner)) { - console.log(chalk.yellow("Prepare transaction to grantRole CONSTANT_SETTER_ROLE to " + owner)); - safeTransactions.push(encodeTransaction( - 0, - messageProxyForMainnet.address, - 0, - messageProxyForMainnet.interface.encodeFunctionData( - "grantRole", - [ await messageProxyForMainnet.CONSTANT_SETTER_ROLE(), owner ] - ) - )); - } - - const newHeaderMessageGasCost = 92251; - - console.log(chalk.yellow( - "Prepare transaction to set header message gas cost to", - newHeaderMessageGasCost.toString() - )); - safeTransactions.push(encodeTransaction( - 0, - messageProxyForMainnet.address, - 0, - messageProxyForMainnet.interface.encodeFunctionData( - "setNewHeaderMessageGasCost", - [ newHeaderMessageGasCost ] - ) - )); - }, + async (safeTransactions, abi) => undefined, "proxyMainnet" ); } From d6de584fd267511a6b6eb3d14da9330c7570885f Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 2 Dec 2022 16:07:57 +0200 Subject: [PATCH 19/20] Update deployed version --- proxy/DEPLOYED | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/DEPLOYED b/proxy/DEPLOYED index 8c9698aaf..10e7a5846 100644 --- a/proxy/DEPLOYED +++ b/proxy/DEPLOYED @@ -1 +1 @@ -1.3.4 \ No newline at end of file +1.3.4-stable.0 \ No newline at end of file From 35a6e40429f850bf2754bcb4891adb5605f9021e Mon Sep 17 00:00:00 2001 From: Dmytro Stebaiev Date: Fri, 2 Dec 2022 16:38:29 +0200 Subject: [PATCH 20/20] Update schain upgrade script --- proxy/migrations/upgradeSchain.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/migrations/upgradeSchain.ts b/proxy/migrations/upgradeSchain.ts index f787263dd..b1cbbd7d8 100644 --- a/proxy/migrations/upgradeSchain.ts +++ b/proxy/migrations/upgradeSchain.ts @@ -14,7 +14,7 @@ async function main() { const pathToManifest: string = stringValue(process.env.MANIFEST); await manifestSetup( pathToManifest ); await upgrade( - "1.3.2", + "1.3.4", contracts, async (safeTransactions, abi) => { // deploying of new contracts