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

feat: added Interchain Router #105

Merged
merged 19 commits into from
Oct 31, 2023
Merged
Changes from 11 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
59 changes: 59 additions & 0 deletions contracts/interfaces/IInterchainRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IContractIdentifier } from './IContractIdentifier.sol';

/**
* @title IRemoteAddressValidator
* @dev Manages and validates remote addresses, keeps track of addresses supported by the Axelar gateway contract
*/
interface IInterchainRouter is IContractIdentifier {
error ZeroAddress();
error LengthMismatch();
error ZeroStringLength();
error UntrustedChain();

event TrustedAddressAdded(string sourceChain, string sourceAddress);
event TrustedAddressRemoved(string sourceChain);

/**
* @dev Gets the name of the chain this is deployed at
*/
function chainName() external view returns (string memory);

/**
* @dev Gets the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return trustedAddress the trusted address for the chain. Returns '' if the chain is untrusted
*/
function getTrustedAddress(string memory chain) external view returns (string memory trustedAddress);

/**
* @dev Gets the trusted address hash at a remote chain
* @param chain Chain name of the remote chain
* @return trustedAddressHash the hash of the trusted address
*/
function getTrustedAddressHash(string memory chain) external view returns (bytes32 trustedAddressHash);

/**
* @dev Validates that the sender is a valid interchain token service address
* @param sourceChain Source chain of the transaction
* @param sourceAddress Source address of the transaction
* @return bool true if the sender is validated, false otherwise
*/
function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool);

/**
* @dev Adds a trusted interchain token service address for the specified chain
* @param sourceChain Chain name of the interchain token service
* @param sourceAddress Interchain token service address to be added
*/
function addTrustedAddress(string memory sourceChain, string memory sourceAddress) external;

/**
* @dev Removes a trusted interchain token service address
* @param sourceChain Chain name of the interchain token service to be removed
*/
function removeTrustedAddress(string calldata sourceChain) external;
}
27 changes: 27 additions & 0 deletions contracts/libs/StringStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library StringStorage {
struct Wrapper {
string value;
}

function store(string memory str, uint256 slot) internal {
_getStringStorage(slot).value = str;
}

function load(uint256 slot) internal view returns (string memory str) {
str = _getStringStorage(slot).value;
}

function del(uint256 slot) internal {
delete _getStringStorage(slot).value;
}

function _getStringStorage(uint256 slot) internal pure returns (Wrapper storage wrapper) {
assembly {
wrapper.slot := slot
}
}
}
21 changes: 21 additions & 0 deletions contracts/test/libs/StringStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { StringStorage } from '../../libs/StringStorage.sol';

contract TestStringStorage {
using StringStorage for string;

function store(uint256 slot, string calldata str) external {
str.store(slot);
}

function load(uint256 slot) external view returns (string memory str) {
str = StringStorage.load(slot);
}

function del(uint256 slot) external {
StringStorage.del(slot);
}
}
15 changes: 15 additions & 0 deletions contracts/test/utils/TestInterchainRouterProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { InterchainRouterProxy } from '../../utils/InterchainRouterProxy.sol';

contract TestInterchainRouterProxy is InterchainRouterProxy {
constructor(
address implementationAddress,
address owner,
bytes memory params
) InterchainRouterProxy(implementationAddress, owner, params) {
contractId();
}
}
153 changes: 153 additions & 0 deletions contracts/utils/InterchainRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IInterchainRouter } from '../interfaces/IInterchainRouter.sol';
import { Upgradable } from '../upgradable/Upgradable.sol';

import { StringStorage } from '../libs/StringStorage.sol';

/**
* @title InterchainRouter
* @dev Manages and validates remote addresses, keeps track of addresses supported by the Axelar gateway contract
*/
contract InterchainRouter is IInterchainRouter, Upgradable {
using StringStorage for string;

bytes32 internal constant PREFIX_ADDRESS_MAPPING = keccak256('interchain-router-address-mapping');
bytes32 internal constant PREFIX_ADDRESS_HASH_MAPPING = keccak256('interchain-router-address-hash-mapping');
// uint256(keccak256('interchain-router-chain-name-slot')) - 1
uint256 internal constant CHAIN_NAME_SLOT = 0x6406a0b603e31e24a15e9f663879eedde3bef27687f318a9875bafac9d63fc1f;

bytes32 private constant CONTRACT_ID = keccak256('interchain-router');

/**
* @dev Constructs the InterchainRouter contract, both array parameters must be equal in length.
* @param chainName_ The name of the current chain.
*/
constructor(string memory chainName_) {
if (bytes(chainName_).length == 0) revert ZeroStringLength();
chainName_.store(CHAIN_NAME_SLOT);
}

/**
* @notice Getter for the contract id.
*/
function contractId() external pure returns (bytes32) {
return CONTRACT_ID;
}

function _setup(bytes calldata params) internal override {
(string[] memory trustedChainNames, string[] memory trustedAddresses) = abi.decode(
params,
(string[], string[])
);
uint256 length = trustedChainNames.length;
if (length != trustedAddresses.length) revert LengthMismatch();

for (uint256 i; i < length; ++i) {
addTrustedAddress(trustedChainNames[i], trustedAddresses[i]);
}
}

/**
* @dev Gets the name of the chain this is deployed at
*/
function chainName() external view returns (string memory chainName_) {
chainName_ = StringStorage.load(CHAIN_NAME_SLOT);
}

/**
* @dev Gets the key for the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return slot the slot to store the trusted address in
*/
function _getTrustedAddressSlot(string memory chain) internal pure returns (uint256 slot) {
slot = uint256(keccak256(abi.encode(PREFIX_ADDRESS_MAPPING, chain)));
}

/**
* @dev Gets the key for the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return slot the slot to store the trusted address hash in
*/
function _getTrustedAddressHashSlot(string memory chain) internal pure returns (uint256 slot) {
slot = uint256(keccak256(abi.encode(PREFIX_ADDRESS_HASH_MAPPING, chain)));
}

/**
* @dev Sets the trusted address and its hash for a remote chain
* @param chain Chain name of the remote chain
* @param trustedAddress the string representation of the trusted address
*/
function _setTrustedAddress(string memory chain, string memory trustedAddress) internal {
trustedAddress.store(_getTrustedAddressSlot(chain));
uint256 slot = _getTrustedAddressHashSlot(chain);
bytes32 addressHash = keccak256(bytes(trustedAddress));
assembly {
sstore(slot, addressHash)
}
}

/**
* @dev Gets the trusted address at a remote chain
* @param chain Chain name of the remote chain
* @return trustedAddress the trusted address for the chain. Returns '' if the chain is untrusted
*/
function getTrustedAddress(string memory chain) public view returns (string memory trustedAddress) {
trustedAddress = StringStorage.load(_getTrustedAddressSlot(chain));
}

/**
* @dev Gets the trusted address hash at a remote chain
* @param chain Chain name of the remote chain
* @return trustedAddressHash the hash of the trusted address
*/
function getTrustedAddressHash(string memory chain) public view returns (bytes32 trustedAddressHash) {
uint256 slot = _getTrustedAddressHashSlot(chain);
assembly {
trustedAddressHash := sload(slot)
}
}

/**
* @dev Validates that the sender is a valid interchain token service address
* @param sourceChain Source chain of the transaction
* @param sourceAddress Source address of the transaction
* @return bool true if the sender is validated, false otherwise
*/
function validateSender(string calldata sourceChain, string calldata sourceAddress) external view returns (bool) {
bytes32 sourceAddressHash = keccak256(bytes(sourceAddress));

return sourceAddressHash == getTrustedAddressHash(sourceChain);
}

/**
* @dev Adds a trusted interchain token service address for the specified chain
* @param sourceChain Chain name of the interchain token service
* @param sourceAddress Interchain token service address to be added
*/
function addTrustedAddress(string memory sourceChain, string memory sourceAddress) public onlyOwner {
if (bytes(sourceChain).length == 0) revert ZeroStringLength();
if (bytes(sourceAddress).length == 0) revert ZeroStringLength();

_setTrustedAddress(sourceChain, sourceAddress);

emit TrustedAddressAdded(sourceChain, sourceAddress);
}

/**
* @dev Removes a trusted interchain token service address
* @param sourceChain Chain name of the interchain token service to be removed
*/
function removeTrustedAddress(string calldata sourceChain) external onlyOwner {
if (bytes(sourceChain).length == 0) revert ZeroStringLength();

StringStorage.del(_getTrustedAddressSlot(sourceChain));
uint256 slot = _getTrustedAddressHashSlot(sourceChain);
assembly {
sstore(slot, 0)
}
emit TrustedAddressRemoved(sourceChain);
}
}
33 changes: 33 additions & 0 deletions contracts/utils/InterchainRouterProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { Proxy } from '../upgradable/Proxy.sol';

/**
* @title InterchainRouterProxy
* @dev Proxy contract for the InterchainRouter contract. Inherits from the Proxy contract.
*/
contract InterchainRouterProxy is Proxy {
bytes32 private constant CONTRACT_ID = keccak256('interchain-router');

/**
* @dev Constructs the InterchainRouterProxy contract.
* @param implementationAddress Address of the InterchainRouter implementation
* @param owner Address of the owner of the proxy
* @param params The params to be passed to the _setup function of the implementation.
*/
constructor(
address implementationAddress,
address owner,
bytes memory params
) Proxy(implementationAddress, owner, params) {}

/**
* @dev Override for the `contractId` function in Proxy. Returns a unique identifier for this contract.
* @return bytes32 Identifier for this contract.
*/
function contractId() internal pure override returns (bytes32) {
return CONTRACT_ID;
}
}
Loading