Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SynapseClient base contract #42

Merged
merged 3 commits into from
Jun 27, 2022
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
74 changes: 74 additions & 0 deletions packages/contracts/contracts/client/Client.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

// ============ Internal Imports ============
import { IMessageRecipient } from "../interfaces/IMessageRecipient.sol";
import { Home } from "../Home.sol";

/// @dev Stateless contract, that can be potentially used as a parent
/// for the upgradeable contract.
abstract contract Client is IMessageRecipient {
// ============ Immutable Variables ============

// local chain Home: used for sending messages
address public immutable home;

// local chain ReplicaManager: used for receiving messages
address public immutable replicaManager;

// ============ Constructor ============

constructor(address _home, address _replicaManager) {
home = _home;
replicaManager = _replicaManager;
}

/**
* @notice Handles an incoming message.
* @dev Can only be called by chain's ReplicaManager.
* Can only be sent from a trusted sender on the remote chain.
* @param _origin Domain of the remote chain, where message originated
* @param _nonce Unique identifier for the message from origin to destination chain
* @param _sender Sender of the message on the origin chain
* @param _message The message
*/
function handle(
uint32 _origin,
uint32 _nonce,
bytes32 _sender,
bytes memory _message
) external {
require(msg.sender == replicaManager, "!replica");
require(_sender == trustedSender(_origin) && _sender != bytes32(0), "!trustedSender");
_handle(_origin, _nonce, _sender, _message);
}

// ============ Virtual Functions ============

/// @dev Internal logic for handling the message, assuming all security checks are passed
function _handle(
uint32 _origin,
uint32 _nonce,
bytes32 _sender,
bytes memory _message
) internal virtual;

/**
* @dev Sends a message to given destination chain.
* @param _destination Domain of the destination chain
* @param _message The message
*/
function _send(uint32 _destination, bytes memory _message) internal {
bytes32 recipient = trustedSender(_destination);
require(recipient != bytes32(0), "!recipient");
Home(home).dispatch(_destination, recipient, _message);
}

/**
* @dev Address of the trusted sender on the destination chain.
* The trusted sender will be able to:
* (1) send messages to this contract
* (2) receive messages from this contract
*/
function trustedSender(uint32 _destination) public view virtual returns (bytes32);
}
70 changes: 70 additions & 0 deletions packages/contracts/contracts/client/SynapseClient.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

// ============ Internal Imports ============
import { Client } from "./Client.sol";
// ============ External Imports ============
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

abstract contract SynapseClient is Client, Ownable {
// ============ Internal Variables ============

/**
* @dev Contracts addresses on the remote chains, which can:
* (1) send messages to this contract
* (2) receive messages from this contract
*/
mapping(uint32 => bytes32) internal trustedSenders;

// ============ Constructor ============

constructor(address _home, address _replicaManager) Client(_home, _replicaManager) {}

// ============ Public Functions ============

/// @notice Returns the trusted sender for the given remote chain.
function trustedSender(uint32 _remoteDomain) public view override returns (bytes32) {
return trustedSenders[_remoteDomain];
}

// ============ Restricted Functions ============

/**
* @notice Sets the trusted sender for the given remote chain.
* @dev Only callable by owner (Governance).
* @param _remoteDomain The domain of the remote chain
* @param _trustedSender The trusted sender
*/
function setTrustedSender(uint32 _remoteDomain, bytes32 _trustedSender) external onlyOwner {
_setTrustedSender(_remoteDomain, _trustedSender);
}

/**
* @notice Sets the trusted sender for a bunch of remote chains.
* @dev Only callable by owner (Governance).
* @param _remoteDomains List of domains for the remote chains
* @param _trustedSenders List of trusted senders for given chains
*/
function setTrustedSenders(uint32[] calldata _remoteDomains, bytes32[] calldata _trustedSenders)
external
onlyOwner
{
uint256 length = _trustedSenders.length;
require(_remoteDomains.length == length, "!arrays");
for (uint256 i = 0; i < length; ) {
_setTrustedSender(_remoteDomains[i], _trustedSenders[i]);
unchecked {
++i;
}
}
}

// ============ Internal Functions ============

/// @dev Checks both domain and trusted sender, then updates the records.
function _setTrustedSender(uint32 _remoteDomain, bytes32 _trustedSender) internal {
require(_remoteDomain != 0, "!domain");
require(_trustedSender != bytes32(0), "!sender");
trustedSenders[_remoteDomain] = _trustedSender;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

// ============ Internal Imports ============
import { Client } from "./Client.sol";
// ============ External Imports ============

import {
OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

abstract contract SynapseClientUpgradeable is Client, OwnableUpgradeable {
// ============ Internal Variables ============

/**
* @dev Contracts addresses on the remote chains, which can:
* (1) send messages to this contract
* (2) receive messages from this contract
*/
mapping(uint32 => bytes32) internal trustedSenders;

// ============ Upgrade gap ============

// gap for upgrade safety
uint256[49] private __GAP;

// ============ Constructor ============

constructor(address _home, address _replicaManager) Client(_home, _replicaManager) {}

// ============ Initializer ============

function __SynapseClient_init() internal onlyInitializing {
__Ownable_init_unchained();
}

function __SynapseClient_init_unchained() internal onlyInitializing {}

// ============ Public Functions ============

/// @notice Returns the trusted sender for the given remote chain.
function trustedSender(uint32 _remoteDomain) public view override returns (bytes32) {
return trustedSenders[_remoteDomain];
}

// ============ Restricted Functions ============

/**
* @notice Sets the trusted sender for the given remote chain.
* @dev Only callable by owner (Governance).
* @param _remoteDomain The domain of the remote chain
* @param _trustedSender The trusted sender
*/
function setTrustedSender(uint32 _remoteDomain, bytes32 _trustedSender) external onlyOwner {
_setTrustedSender(_remoteDomain, _trustedSender);
}

/**
* @notice Sets the trusted sender for a bunch of remote chains.
* @dev Only callable by owner (Governance).
* @param _remoteDomains List of domains for the remote chains
* @param _trustedSenders List of trusted senders for given chains
*/
function setTrustedSenders(uint32[] calldata _remoteDomains, bytes32[] calldata _trustedSenders)
external
onlyOwner
{
uint256 length = _trustedSenders.length;
require(_remoteDomains.length == length, "!arrays");
for (uint256 i = 0; i < length; ) {
_setTrustedSender(_remoteDomains[i], _trustedSenders[i]);
unchecked {
++i;
}
}
}

// ============ Internal Functions ============

/// @dev Checks both domain and trusted sender, then updates the records.
function _setTrustedSender(uint32 _remoteDomain, bytes32 _trustedSender) internal {
require(_remoteDomain != 0, "!domain");
require(_trustedSender != bytes32(0), "!sender");
trustedSenders[_remoteDomain] = _trustedSender;
}
}
Loading