diff --git a/contracts/app/Bridge.sol b/contracts/app/Bridge.sol index feaa46d..31c8887 100644 --- a/contracts/app/Bridge.sol +++ b/contracts/app/Bridge.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../DynamicMerkleTree.sol"; @@ -11,6 +12,7 @@ library BridgeLib { address tokenAddress; address destination; uint256 amount; + uint256 fee; uint256 startTime; uint256 feeRampup; } @@ -33,17 +35,24 @@ contract BridgeSource { constructor() {} function withdraw( + address sourceTokenAddress, BridgeLib.TransferData memory transferData, bytes32[] memory proof - ) public { + ) public payable { // safemath not needed for solidity 8 uint256 amountPlusFee = (transferData.amount * (10000 + CONTRACT_FEE_BASIS_POINTS)) / 10000; - IERC20(transferData.tokenAddress).safeTransferFrom( - msg.sender, - address(this), - amountPlusFee - ); + + if (sourceTokenAddress == address(0)) { + require(msg.value >= amountPlusFee, "not enough msg.value"); + payable(address(this)).transfer(amountPlusFee); + } else { + IERC20(sourceTokenAddress).safeTransferFrom( + msg.sender, + address(this), + amountPlusFee + ); + } BridgeLib.TransferInitiated memory transferInitiated = BridgeLib .TransferInitiated({data: transferData, self: address(this)}); @@ -61,7 +70,7 @@ contract BridgeSource { } } -contract BridgeDestination { +contract BridgeDestination is ReentrancyGuard { using SafeERC20 for IERC20; struct TransferKey { @@ -99,18 +108,32 @@ contract BridgeDestination { view returns (uint256) { - // TODO: - return 0; + uint256 currentTime = block.timestamp; + if (currentTime < transferData.startTime) { + return 0; + } else if ( + currentTime >= transferData.startTime + transferData.feeRampup + ) { + return transferData.fee; + } else { + return transferData.fee * (currentTime - transferData.startTime); + } } - function buy(TransferKey memory tkey) public { + function buy(TransferKey memory tkey) public payable nonReentrant { uint256 amount = tkey.transferData.amount - getLPFee(tkey.transferData); - // TODO: another token address on dest. chain? - IERC20(tkey.transferData.tokenAddress).safeTransferFrom( - msg.sender, - tkey.transferData.destination, - amount - ); + + if (tkey.transferData.tokenAddress == address(0)) { + require(msg.value >= amount, "not enough msg.value"); + payable(tkey.transferData.destination).transfer(amount); + } else { + // TODO: another token address on dest. chain? + IERC20(tkey.transferData.tokenAddress).safeTransferFrom( + msg.sender, + tkey.transferData.destination, + amount + ); + } bytes32 key = keccak256(abi.encode(tkey)); require(ownerMap[key] == address(0), "already bought or withdrawn"); @@ -124,7 +147,7 @@ contract BridgeDestination { address sourceContract, uint256 transferLen, bytes32[] memory recordProof - ) public { + ) public nonReentrant { if (!validatedStateRoots[stateRoot]) { // TODO: prove stateRoot is in stateRootProof validatedStateRoots[stateRoot] = true; @@ -143,16 +166,27 @@ contract BridgeDestination { bytes32 key = keccak256(abi.encode(tkey)); require(ownerMap[key] != address(2**160 - 1), "already withdrawn"); - if (ownerMap[key] == address(0)) { - IERC20(tkey.transferData.tokenAddress).safeTransfer( - tkey.transferData.destination, - tkey.transferData.amount - ); + + if (tkey.transferData.tokenAddress != address(0)) { + if (ownerMap[key] == address(0)) { + IERC20(tkey.transferData.tokenAddress).safeTransfer( + tkey.transferData.destination, + tkey.transferData.amount + ); + } else { + IERC20(tkey.transferData.tokenAddress).safeTransfer( + ownerMap[key], + tkey.transferData.amount + ); + } } else { - IERC20(tkey.transferData.tokenAddress).safeTransfer( - ownerMap[key], - tkey.transferData.amount - ); + if (ownerMap[key] == address(0)) { + payable(tkey.transferData.destination).transfer( + tkey.transferData.amount + ); + } else { + payable(ownerMap[key]).transfer(tkey.transferData.amount); + } } ownerMap[key] = address(2**160 - 1); // -1, not used any more