Skip to content

Commit

Permalink
feat: Add test to protocol contracts (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
andresaiello authored Nov 7, 2023
1 parent accb3cb commit 9bfba6f
Show file tree
Hide file tree
Showing 47 changed files with 6,080 additions and 49 deletions.
7 changes: 2 additions & 5 deletions contracts/evm/ERC20Custody.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ contract ERC20Custody is ReentrancyGuard {
/**
* @dev Pause custody operations.
*/
function pause() external onlyTSSUpdater {
function pause() external onlyTSS {
if (paused) {
revert IsPaused();
}
Expand All @@ -129,7 +129,7 @@ contract ERC20Custody is ReentrancyGuard {
/**
* @dev Unpause custody operations.
*/
function unpause() external onlyTSSUpdater {
function unpause() external onlyTSS {
if (!paused) {
revert NotPaused();
}
Expand Down Expand Up @@ -191,9 +191,6 @@ contract ERC20Custody is ReentrancyGuard {
* @param amount, asset amount.
*/
function withdraw(address recipient, IERC20 asset, uint256 amount) external nonReentrant onlyTSS {
if (paused) {
revert IsPaused();
}
if (!whitelisted[asset]) {
revert NotWhitelisted();
}
Expand Down
54 changes: 54 additions & 0 deletions contracts/evm/testing/AttackerContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface Victim {
function deposit(bytes calldata recipient, address asset, uint256 amount, bytes calldata message) external;

function withdraw(address recipient, address asset, uint256 amount) external;
}

contract AttackerContract {
address public victimContractAddress;
uint256 private _victimMethod;

constructor(address victimContractAddress_, address wzeta, uint256 victimMethod) {
victimContractAddress = victimContractAddress_;
IERC20(wzeta).approve(victimContractAddress, type(uint256).max);
_victimMethod = victimMethod;
}

// Fallback function to receive ETH
receive() external payable {}

function attackDeposit() internal {
Victim(victimContractAddress).deposit("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", address(this), 0, "0x00");
}

function attackWidrawal() internal {
Victim(victimContractAddress).withdraw(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, address(this), 0);
}

function attack() internal {
if (_victimMethod == 1) {
attackDeposit();
} else if (_victimMethod == 2) {
attackWidrawal();
}
}

function balanceOf(address account) external returns (uint256) {
attack();
return 0;
}

function transferFrom(address from, address to, uint256 amount) public returns (bool) {
attack();
return true;
}

function transfer(address to, uint256 amount) public returns (bool) {
attack();
return true;
}
}
13 changes: 13 additions & 0 deletions contracts/evm/testing/ERC20Mock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
* @dev ZetaEth is an implementation of OpenZeppelin's ERC20
*/
contract ERC20Mock is ERC20 {
constructor(string memory name, string memory symbol, address creator, uint256 initialSupply) ERC20(name, symbol) {
_mint(creator, initialSupply * (10 ** uint256(decimals())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ contract ZetaConnectorZEVM is ZetaInterfaces {
);
event SetWZETA(address wzeta_);

constructor(address _wzeta) {
wzeta = _wzeta;
constructor(address wzeta_) {
wzeta = wzeta_;
}

/// @dev Receive function to receive ZETA from WETH9.withdraw().
Expand Down
85 changes: 85 additions & 0 deletions contracts/zevm/testing/SystemContractMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "../interfaces/zContract.sol";
import "../interfaces/IZRC20.sol";

interface SystemContractErrors {
error CallerIsNotFungibleModule();

error InvalidTarget();

error CantBeIdenticalAddresses();

error CantBeZeroAddress();
}

contract SystemContractMock is SystemContractErrors {
mapping(uint256 => uint256) public gasPriceByChainId;
mapping(uint256 => address) public gasCoinZRC20ByChainId;
mapping(uint256 => address) public gasZetaPoolByChainId;

address public wZetaContractAddress;
address public uniswapv2FactoryAddress;
address public uniswapv2Router02Address;

event SystemContractDeployed();
event SetGasPrice(uint256, uint256);
event SetGasCoin(uint256, address);
event SetGasZetaPool(uint256, address);
event SetWZeta(address);

constructor(address wzeta_, address uniswapv2Factory_, address uniswapv2Router02_) {
wZetaContractAddress = wzeta_;
uniswapv2FactoryAddress = uniswapv2Factory_;
uniswapv2Router02Address = uniswapv2Router02_;
emit SystemContractDeployed();
}

// fungible module updates the gas price oracle periodically
function setGasPrice(uint256 chainID, uint256 price) external {
gasPriceByChainId[chainID] = price;
emit SetGasPrice(chainID, price);
}

function setGasCoinZRC20(uint256 chainID, address zrc20) external {
gasCoinZRC20ByChainId[chainID] = zrc20;
emit SetGasCoin(chainID, zrc20);
}

function setWZETAContractAddress(address addr) external {
wZetaContractAddress = addr;
emit SetWZeta(wZetaContractAddress);
}

// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
if (tokenA == tokenB) revert CantBeIdenticalAddresses();
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
if (token0 == address(0)) revert CantBeZeroAddress();
}

function uniswapv2PairFor(address factory, address tokenA, address tokenB) public pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1)),
hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash
)
)
)
)
);
}

function onCrossChainCall(address target, address zrc20, uint256 amount, bytes calldata message) external {
zContext memory context = zContext({sender: msg.sender, origin: "", chainID: block.chainid});
IZRC20(zrc20).transfer(target, amount);
zContract(target).onCrossChainCall(context, zrc20, amount, message);
}
}
2 changes: 1 addition & 1 deletion pkg/contracts/evm/erc20custody.sol/erc20custody.go

Large diffs are not rendered by default.

Loading

0 comments on commit 9bfba6f

Please sign in to comment.