Skip to content
This repository was archived by the owner on May 9, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"solidity.compileUsingRemoteVersion": "v0.8.11+commit.d7f03943",
"solidity.defaultCompiler": "remote"
}
80 changes: 52 additions & 28 deletions contracts/Bridge.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "./utils/AccessControl.sol";
import "./utils/Pausable.sol";
Expand All @@ -9,6 +8,7 @@ import "./utils/SafeCast.sol";
import "./interfaces/IDepositExecute.sol";
import "./interfaces/IERCHandler.sol";
import "./interfaces/IGenericHandler.sol";
import "./interfaces/IFeeHandler.sol";

/**
@title Facilitates deposits, creation and voting of deposit proposals, and deposit executions.
Expand All @@ -22,9 +22,10 @@ contract Bridge is Pausable, AccessControl, SafeMath {

uint8 public _domainID;
uint8 public _relayerThreshold;
uint128 public _fee;
uint40 public _expiry;

IFeeHandler public _feeHandler;

enum ProposalStatus {Inactive, Active, Passed, Executed, Cancelled}

struct Proposal {
Expand All @@ -46,6 +47,7 @@ contract Bridge is Pausable, AccessControl, SafeMath {
event RelayerThresholdChanged(uint256 newThreshold);
event RelayerAdded(address relayer);
event RelayerRemoved(address relayer);
event FeeHandlerChanged(address newFeeHandler);
event Deposit(
uint8 destinationDomainID,
bytes32 resourceID,
Expand Down Expand Up @@ -126,10 +128,9 @@ contract Bridge is Pausable, AccessControl, SafeMath {
@param initialRelayers Addresses that should be initially granted the relayer role.
@param initialRelayerThreshold Number of votes needed for a deposit proposal to be considered passed.
*/
constructor (uint8 domainID, address[] memory initialRelayers, uint256 initialRelayerThreshold, uint256 fee, uint256 expiry) public {
constructor (uint8 domainID, address[] memory initialRelayers, uint256 initialRelayerThreshold, uint256 expiry) public {
_domainID = domainID;
_relayerThreshold = initialRelayerThreshold.toUint8();
_fee = fee.toUint128();
_expiry = expiry.toUint40();

_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
Expand Down Expand Up @@ -290,6 +291,17 @@ contract Bridge is Pausable, AccessControl, SafeMath {
function adminSetForwarder(address forwarder, bool valid) external onlyAdmin {
isValidForwarder[forwarder] = valid;
}

function adminSetWtoken(
bytes32 resourceID,
address wtokenAddress,
bool isWtoken
) external onlyAdmin {
IERCHandler handler = IERCHandler(
_resourceIDToHandlerAddress[resourceID]
);
handler.setWtoken(wtokenAddress, isWtoken);
}

/**
@notice Returns a proposal.
Expand All @@ -316,13 +328,13 @@ contract Bridge is Pausable, AccessControl, SafeMath {
}

/**
@notice Changes deposit fee.
@notice Changes deposit fee handler contract address.
@notice Only callable by admin.
@param newFee Value {_fee} will be updated to.
@param newFeeHandler Address {_feeHandler} will be updated to.
*/
function adminChangeFee(uint256 newFee) external onlyAdmin {
require(_fee != newFee, "Current fee is equal to new fee");
_fee = newFee.toUint128();
function adminChangeFeeHandler(address newFeeHandler) external onlyAdmin {
_feeHandler = IFeeHandler(newFeeHandler);
emit FeeHandlerChanged(newFeeHandler);
}

/**
Expand All @@ -338,30 +350,54 @@ contract Bridge is Pausable, AccessControl, SafeMath {
handler.withdraw(data);
}

function adminWithdrawETH(
address handlerAddress,
bytes memory data
) external onlyAdmin {
IERCHandler handler = IERCHandler(handlerAddress);
handler.withdrawETH(data);
}

/**
@notice Initiates a transfer using a specified handler contract.
@notice Only callable when Bridge is not paused.
@param destinationDomainID ID of chain deposit will be bridged to.
@param resourceID ResourceID used to find address of handler to be used for deposit.
@param data Additional data to be passed to specified handler.
@param depositData Additional data to be passed to specified handler.
@param feeData Additional data to be passed to the fee handler.
@notice Emits {Deposit} event with all necessary parameters and a handler response.
- ERC20Handler: responds with an empty data.
- ERC721Handler: responds with the deposited token metadata acquired by calling a tokenURI method in the token contract.
- GenericHandler: responds with the raw bytes returned from the call to the target contract.
*/
function deposit(uint8 destinationDomainID, bytes32 resourceID, bytes calldata data) external payable whenNotPaused {
require(msg.value == _fee, "Incorrect fee supplied");
function deposit(uint8 destinationDomainID, bytes32 resourceID, bytes calldata depositData, bytes calldata feeData) external payable whenNotPaused {
address sender = _msgSender();
uint256 value = msg.value;
if (address(_feeHandler) == address(0)) {
(uint256 fee, ) = _feeHandler.calculateFee(
sender,
_domainID,
destinationDomainID,
resourceID,
depositData,
feeData
);
if (fee > 0) {
// Reverts on failure
_feeHandler.collectFee{value: msg.value}(sender, _domainID, destinationDomainID, resourceID, depositData, feeData);
value -= fee;
}
}

address handler = _resourceIDToHandlerAddress[resourceID];
require(handler != address(0), "resourceID not mapped to handler");

uint64 depositNonce = ++_depositCounts[destinationDomainID];
address sender = _msgSender();

IDepositExecute depositHandler = IDepositExecute(handler);
bytes memory handlerResponse = depositHandler.deposit(resourceID, sender, data);

emit Deposit(destinationDomainID, resourceID, depositNonce, sender, data, handlerResponse);
bytes memory handlerResponse = depositHandler.deposit{value: value}(resourceID, sender, depositData);
emit Deposit(destinationDomainID, resourceID, depositNonce, sender, depositData, handlerResponse);
}

/**
Expand Down Expand Up @@ -490,16 +526,4 @@ contract Bridge is Pausable, AccessControl, SafeMath {

emit ProposalEvent(domainID, depositNonce, ProposalStatus.Executed, dataHash);
}

/**
@notice Transfers eth in the contract to the specified addresses. The parameters addrs and amounts are mapped 1-1.
This means that the address at index 0 for addrs will receive the amount (in WEI) from amounts at index 0.
@param addrs Array of addresses to transfer {amounts} to.
@param amounts Array of amonuts to transfer to {addrs}.
*/
function transferFunds(address payable[] calldata addrs, uint[] calldata amounts) external onlyAdmin {
for (uint256 i = 0; i < addrs.length; i++) {
addrs[i].transfer(amounts[i]);
}
}
}
1 change: 0 additions & 1 deletion contracts/CentrifugeAsset.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

/**
@title Represents a bridged Centrifuge asset.
Expand Down
32 changes: 32 additions & 0 deletions contracts/ERC20Safe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
*/
contract ERC20Safe {
using SafeMath for uint256;
uint256 public ETHReserve;

/**
@notice Used to gain custody of deposited token.
Expand All @@ -37,6 +38,24 @@ contract ERC20Safe {
_safeTransfer(erc20, recipient, amount);
}

function depositETH(uint256 amount) internal {
require(amount == msg.value, "msg.value and data mismatched");
require(
address(this).balance >= ETHReserve + amount,
"ETHReserve mismatched"
);
ETHReserve = address(this).balance;
}

function withdrawETH(address recipient, uint256 amount) internal {
uint256 balanceBefore = address(this).balance;
_safeTransferETH(recipient, amount);
require(
address(this).balance == balanceBefore - amount,
"ERC20: withdraw fail!"
);
}

/**
@notice Used to create new ERC20s.
@param tokenAddress Address of ERC20 to transfer.
Expand Down Expand Up @@ -70,6 +89,19 @@ contract ERC20Safe {
_safeCall(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}

function _safeTransferETH(address to, uint256 value) private {
(bool success, bytes memory returndata) = address(to).call{
value: value
}("");
require(success, "ERC20: call failed");

if (returndata.length > 0) {
require(
abi.decode(returndata, (bool)),
"ERC20: operation did not succeed"
);
}
}

/**
@notice used to transfer ERC20s safely
Expand Down
2 changes: 1 addition & 1 deletion contracts/ERC721MinterBurnerPauser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract ERC721MinterBurnerPauser is Context, AccessControl, ERC721Burnable, ERC
* Token URIs will be autogenerated based on `baseURI` and their token IDs.
* See {ERC721-tokenURI}.
*/
constructor(string memory name, string memory symbol, string memory baseURI) public ERC721(name, symbol) {
constructor(string memory name, string memory symbol, string memory baseURI) ERC721(name, symbol) {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());

_setupRole(MINTER_ROLE, _msgSender());
Expand Down
1 change: 0 additions & 1 deletion contracts/Forwarder.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
Expand Down
1 change: 0 additions & 1 deletion contracts/TestContracts.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "./utils/SafeCast.sol";
import "./handlers/HandlerHelpers.sol";
Expand Down
6 changes: 3 additions & 3 deletions contracts/handlers/ERC1155Handler.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "../interfaces/IDepositExecute.sol";
import "./HandlerHelpers.sol";
Expand All @@ -20,7 +19,7 @@ contract ERC1155Handler is IDepositExecute, HandlerHelpers, ERC1155Safe, ERC1155
*/
constructor(
address bridgeAddress
) public HandlerHelpers(bridgeAddress) {
) HandlerHelpers(bridgeAddress) {
}

/**
Expand All @@ -29,7 +28,8 @@ contract ERC1155Handler is IDepositExecute, HandlerHelpers, ERC1155Safe, ERC1155
@param depositer Address of account making the deposit in the Bridge contract.
@param data Consists of ABI-encoded arrays of tokenIDs and amounts.
*/
function deposit(bytes32 resourceID, address depositer, bytes calldata data) external override onlyBridge returns (bytes memory metaData) {
function deposit(bytes32 resourceID, address depositer, bytes calldata data) external payable override onlyBridge returns (bytes memory metaData) {
require(msg.value == 0, "msg.value != 0");
uint[] memory tokenIDs;
uint[] memory amounts;

Expand Down
25 changes: 22 additions & 3 deletions contracts/handlers/ERC20Handler.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "../interfaces/IDepositExecute.sol";
import "./HandlerHelpers.sol";
Expand All @@ -17,7 +16,7 @@ contract ERC20Handler is IDepositExecute, HandlerHelpers, ERC20Safe {
*/
constructor(
address bridgeAddress
) public HandlerHelpers(bridgeAddress) {
) HandlerHelpers(bridgeAddress) {
}

/**
Expand All @@ -35,7 +34,7 @@ contract ERC20Handler is IDepositExecute, HandlerHelpers, ERC20Safe {
bytes32 resourceID,
address depositer,
bytes calldata data
) external override onlyBridge returns (bytes memory) {
) external payable override onlyBridge returns (bytes memory) {
uint256 amount;
(amount) = abi.decode(data, (uint));

Expand All @@ -44,6 +43,8 @@ contract ERC20Handler is IDepositExecute, HandlerHelpers, ERC20Safe {

if (_burnList[tokenAddress]) {
burnERC20(tokenAddress, depositer, amount);
} else if (isWtoken[tokenAddress]) {
depositETH(amount);
} else {
lockERC20(tokenAddress, depositer, address(this), amount);
}
Expand Down Expand Up @@ -78,6 +79,8 @@ contract ERC20Handler is IDepositExecute, HandlerHelpers, ERC20Safe {

if (_burnList[tokenAddress]) {
mintERC20(tokenAddress, address(recipientAddress), amount);
} else if (isWtoken[tokenAddress]) {
withdrawETH(address(recipientAddress), amount);
} else {
releaseERC20(tokenAddress, address(recipientAddress), amount);
}
Expand All @@ -100,4 +103,20 @@ contract ERC20Handler is IDepositExecute, HandlerHelpers, ERC20Safe {

releaseERC20(tokenAddress, recipient, amount);
}

/**
@notice Used to manually release ETH ERC20Safe.
@param data Consists of {recipient}, and {amount} all padded to 32 bytes.
@notice Data passed into the function should be constructed as follows:
recipient address bytes 0 - 32
amount uint bytes 32 - 64
*/
function withdrawETH(bytes memory data) external override onlyBridge {
address recipient;
uint amount;

(recipient, amount) = abi.decode(data, (address, uint));

withdrawETH(recipient, amount);
}
}
6 changes: 3 additions & 3 deletions contracts/handlers/ERC721Handler.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "../interfaces/IDepositExecute.sol";
import "./HandlerHelpers.sol";
Expand All @@ -24,7 +23,7 @@ contract ERC721Handler is IDepositExecute, HandlerHelpers, ERC721Safe {
*/
constructor(
address bridgeAddress
) public HandlerHelpers(bridgeAddress) {
) HandlerHelpers(bridgeAddress) {
}

/**
Expand All @@ -43,7 +42,8 @@ contract ERC721Handler is IDepositExecute, HandlerHelpers, ERC721Safe {
function deposit(bytes32 resourceID,
address depositer,
bytes calldata data
) external override onlyBridge returns (bytes memory metaData) {
) external payable override onlyBridge returns (bytes memory metaData) {
require(msg.value == 0, "msg.value != 0");
uint tokenID;

(tokenID) = abi.decode(data, (uint));
Expand Down
3 changes: 1 addition & 2 deletions contracts/handlers/GenericHandler.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity 0.8.11;
pragma experimental ABIEncoderV2;

import "../interfaces/IGenericHandler.sol";

Expand Down Expand Up @@ -87,7 +86,7 @@ contract GenericHandler is IGenericHandler {
{metaData} is expected to consist of needed function arguments.
@return Returns the raw bytes returned from the call to {contractAddress}.
*/
function deposit(bytes32 resourceID, address depositer, bytes calldata data) external onlyBridge returns (bytes memory) {
function deposit(bytes32 resourceID, address depositer, bytes calldata data) external payable onlyBridge returns (bytes memory) {
uint256 lenMetadata;
bytes memory metadata;

Expand Down
Loading