Skip to content
Merged
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
132 changes: 132 additions & 0 deletions packages/contracts/contracts/L1/teleportr/TeleportrDeposit.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title TeleportrDeposit
*
* Shout out to 0xclem for providing the inspiration for this contract:
* https://github.com/0xclem/teleportr/blob/main/contracts/BridgeDeposit.sol
*/
contract TeleportrDeposit is Ownable {
/// The minimum amount that be deposited in a receive.
uint256 public minDepositAmount;
/// The maximum amount that be deposited in a receive.
uint256 public maxDepositAmount;
/// The maximum balance the contract can hold after a receive.
uint256 public maxBalance;
/// The total number of successful deposits received.
uint256 public totalDeposits;

/**
* @notice Emitted any time the minimum deposit amount is set.
* @param previousAmount The previous minimum deposit amount.
* @param newAmount The new minimum deposit amount.
*/
event MinDepositAmountSet(uint256 previousAmount, uint256 newAmount);

/**
* @notice Emitted any time the maximum deposit amount is set.
* @param previousAmount The previous maximum deposit amount.
* @param newAmount The new maximum deposit amount.
*/
event MaxDepositAmountSet(uint256 previousAmount, uint256 newAmount);

/**
* @notice Emitted any time the contract maximum balance is set.
* @param previousBalance The previous maximum contract balance.
* @param newBalance The new maximum contract balance.
*/
event MaxBalanceSet(uint256 previousBalance, uint256 newBalance);

/**
* @notice Emitted any time the balance is withdrawn by the owner.
* @param owner The current owner and recipient of the funds.
* @param balance The current contract balance paid to the owner.
*/
event BalanceWithdrawn(address indexed owner, uint256 balance);

/**
* @notice Emitted any time a successful deposit is received.
* @param depositId A unique sequencer number identifying the deposit.
* @param emitter The sending address of the payer.
* @param amount The amount deposited by the payer.
*/
event EtherReceived(uint256 indexed depositId, address indexed emitter, uint256 indexed amount);

/**
* @notice Initializes a new TeleportrDeposit contract.
* @param _minDepositAmount The initial minimum deposit amount.
* @param _maxDepositAmount The initial maximum deposit amount.
* @param _maxBalance The initial maximum contract balance.
*/
constructor(
uint256 _minDepositAmount,
uint256 _maxDepositAmount,
uint256 _maxBalance
) {
minDepositAmount = _minDepositAmount;
maxDepositAmount = _maxDepositAmount;
maxBalance = _maxBalance;
totalDeposits = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this is a noop. State vars are initialized to zero:

The concept of “undefined” or “null” values does not exist in Solidity, but newly declared variables always have a default value dependent on its type.

Source: Types — Solidity 0.8.13 documentation

emit MinDepositAmountSet(0, _minDepositAmount);
emit MaxDepositAmountSet(0, _maxDepositAmount);
emit MaxBalanceSet(0, _maxBalance);
}

/**
* @notice Accepts deposits that will be disbursed to the sender's address on L2.
* The method reverts if the amount is less than the current
* minDepositAmount, the amount is greater than the current
* maxDepositAmount, or the amount causes the contract to exceed its maximum
* allowed balance.
*/
receive() external payable {
require(msg.value >= minDepositAmount, "Deposit amount is too small");
require(msg.value <= maxDepositAmount, "Deposit amount is too big");
require(address(this).balance <= maxBalance, "Contract max balance exceeded");
Comment on lines +86 to +88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this is much more readable than modifiers IMO.


emit EtherReceived(totalDeposits, msg.sender, msg.value);
unchecked {
totalDeposits += 1;
}
}

/**
* @notice Sends the contract's current balance to the owner.
*/
function withdrawBalance() external onlyOwner {
address _owner = owner();
uint256 _balance = address(this).balance;
emit BalanceWithdrawn(_owner, _balance);
payable(_owner).transfer(_balance);
}

/**
* @notice Sets the minimum amount that can be deposited in a receive.
* @param _minDepositAmount The new minimum deposit amount.
*/
function setMinAmount(uint256 _minDepositAmount) external onlyOwner {
emit MinDepositAmountSet(minDepositAmount, _minDepositAmount);
minDepositAmount = _minDepositAmount;
}

/**
* @notice Sets the maximum amount that can be deposited in a receive.
* @param _maxDepositAmount The new maximum deposit amount.
*/
function setMaxAmount(uint256 _maxDepositAmount) external onlyOwner {
emit MaxDepositAmountSet(maxDepositAmount, _maxDepositAmount);
maxDepositAmount = _maxDepositAmount;
}

/**
* @notice Sets the maximum balance the contract can hold after a receive.
* @param _maxBalance The new maximum contract balance.
*/
function setMaxBalance(uint256 _maxBalance) external onlyOwner {
emit MaxBalanceSet(maxBalance, _maxBalance);
maxBalance = _maxBalance;
}
}
115 changes: 115 additions & 0 deletions packages/contracts/contracts/L2/teleportr/TeleportrDisburser.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title TeleportrDisburser
*/
contract TeleportrDisburser is Ownable {
/**
* @notice A struct holding the address and amount to disbursement.
*/
struct Disbursement {
uint256 amount;
address addr;
}

/// The total number of disbursements processed.
uint256 public totalDisbursements;

/**
* @notice Emitted any time the balance is withdrawn by the owner.
* @param owner The current owner and recipient of the funds.
* @param balance The current contract balance paid to the owner.
*/
event BalanceWithdrawn(address indexed owner, uint256 balance);

/**
* @notice Emitted any time a disbursement is successfuly sent.
* @param depositId The unique sequence number identifying the deposit.
* @param to The recipient of the disbursement.
* @param amount The amount sent to the recipient.
*/
event DisbursementSuccess(uint256 indexed depositId, address indexed to, uint256 amount);

/**
* @notice Emitted any time a disbursement fails to send.
* @param depositId The unique sequence number identifying the deposit.
* @param to The intended recipient of the disbursement.
* @param amount The amount intended to be sent to the recipient.
*/
event DisbursementFailed(uint256 indexed depositId, address indexed to, uint256 amount);

/**
* @notice Initializes a new TeleportrDisburser contract.
*/
constructor() {
totalDisbursements = 0;
}

/**
* @notice Accepts a list of Disbursements and forwards the amount paid to
* the contract to each recipient. The method reverts if there are zero
* disbursements, the total amount to forward differs from the amount sent
* in the transaction, or the _nextDepositId is unexpected. Failed
* disbursements will not cause the method to revert, but will instead be
* held by the contract and availabe for the owner to withdraw.
* @param _nextDepositId The depositId of the first Dispursement.
* @param _disbursements A list of Disbursements to process.
*/
function disburse(uint256 _nextDepositId, Disbursement[] calldata _disbursements)
external
payable
onlyOwner
{
// Ensure there are disbursements to process.
uint256 _numDisbursements = _disbursements.length;
require(_numDisbursements > 0, "No disbursements");

// Ensure the _nextDepositId matches our expected value.
uint256 _depositId = totalDisbursements;
require(_depositId == _nextDepositId, "Unexpected next deposit id");
unchecked {
totalDisbursements += _numDisbursements;
}

// Ensure the amount sent in the transaction is equal to the sum of the
// disbursements.
uint256 _totalDisbursed = 0;
for (uint256 i = 0; i < _numDisbursements; i++) {
_totalDisbursed += _disbursements[i].amount;
}
require(_totalDisbursed == msg.value, "Disbursement total != amount sent");

// Process disbursements.
for (uint256 i = 0; i < _numDisbursements; i++) {
uint256 _amount = _disbursements[i].amount;
address _addr = _disbursements[i].addr;

// Deliver the dispursement amount to the receiver. If the
// disbursement fails, the amount will be kept by the contract
// rather than reverting to prevent blocking progress on other
// disbursements.

// slither-disable-next-line calls-loop,reentrancy-events
(bool success, ) = _addr.call{ value: _amount, gas: 2300 }("");
if (success) emit DisbursementSuccess(_depositId, _addr, _amount);
else emit DisbursementFailed(_depositId, _addr, _amount);

unchecked {
_depositId += 1;
}
}
}

/**
* @notice Sends the contract's current balance to the owner.
*/
function withdrawBalance() external onlyOwner {
address _owner = owner();
uint256 balance = address(this).balance;
emit BalanceWithdrawn(_owner, balance);
payable(_owner).transfer(balance);
}
}
14 changes: 14 additions & 0 deletions packages/contracts/contracts/test-helpers/FailingReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

/**
* @title FailingReceiver
*/
contract FailingReceiver {
/**
* @notice Receiver that always reverts upon receiving ether.
*/
receive() external payable {
require(false, "FailingReceiver");
}
}
12 changes: 12 additions & 0 deletions packages/contracts/docs/FailingReceiver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# FailingReceiver



> FailingReceiver







Loading