Skip to content

Commit

Permalink
Merge pull request #38 from gnosis/feat/v0.2.0-adapters
Browse files Browse the repository at this point in the history
feat: Adapters - v0.2.0
  • Loading branch information
allemanfredi authored Jan 29, 2024
2 parents 544a7ab + 3c55b2f commit 6836e2b
Show file tree
Hide file tree
Showing 80 changed files with 813 additions and 3,188 deletions.
47 changes: 21 additions & 26 deletions packages/evm/contracts/adapters/AMB/AMBAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,37 @@
pragma solidity ^0.8.17;

import { IAMB } from "./IAMB.sol";
import { OracleAdapter } from "../OracleAdapter.sol";
import { BlockHashOracleAdapter } from "../BlockHashOracleAdapter.sol";

contract AMBAdapter is OracleAdapter, BlockHashOracleAdapter {
IAMB public amb;
address public reporter;
bytes32 public chainId;
contract AMBAdapter is BlockHashOracleAdapter {
string public constant PROVIDER = "amb";

error ArrayLengthMissmatch(address emitter);
error UnauthorizedAMB(address emitter, address sender);
error UnauthorizedChainId(address emitter, bytes32 chainId);
error UnauthorizedHashReporter(address emitter, address reporter);
IAMB public immutable AMB;
address public immutable REPORTER;
bytes32 public immutable SOURCE_CHAIN_ID;

constructor(IAMB _amb, address _reporter, bytes32 _chainId) {
amb = _amb;
reporter = _reporter;
chainId = _chainId;
error ArrayLengthMissmatch();
error UnauthorizedAMB(address sender, address expectedSender);
error UnauthorizedChainId(bytes32 sourceChainId, bytes32 expectedSourceChainId);
error UnauthorizedHashReporter(address reporter, address expectedReporter);

constructor(address amb, address reporter, bytes32 sourceChainId) {
AMB = IAMB(amb);
REPORTER = reporter;
SOURCE_CHAIN_ID = sourceChainId;
}

/// @dev Check that the amb, chainId, and owner are valid.
modifier onlyValid() {
if (msg.sender != address(amb)) revert UnauthorizedAMB(address(this), msg.sender);
if (amb.messageSourceChainId() != chainId) revert UnauthorizedChainId(address(this), chainId);
if (amb.messageSender() != reporter) revert UnauthorizedHashReporter(address(this), reporter);
bytes32 ambSourceChainId = AMB.messageSourceChainId();
address ambMessageSender = AMB.messageSender();
if (msg.sender != address(AMB)) revert UnauthorizedAMB(msg.sender, address(AMB));
if (ambSourceChainId != SOURCE_CHAIN_ID) revert UnauthorizedChainId(ambSourceChainId, SOURCE_CHAIN_ID);
if (ambMessageSender != REPORTER) revert UnauthorizedHashReporter(ambMessageSender, REPORTER);
_;
}

/// @dev Stores the hashes for a given array of idss.
/// @param ids Array of ids number for which to set the hashes.
/// @param _hashes Array of hashes to set for the given ids.
/// @notice Only callable by `amb` with a message passed from `reporter.
/// @notice Will revert if given array lengths do not match.
function storeHashes(uint256[] memory ids, bytes32[] memory _hashes) public onlyValid {
if (ids.length != _hashes.length) revert ArrayLengthMissmatch(address(this));
for (uint256 i = 0; i < ids.length; i++) {
_storeHash(uint256(chainId), ids[i], _hashes[i]);
}
if (ids.length != _hashes.length) revert ArrayLengthMissmatch();
_storeHashes(uint256(SOURCE_CHAIN_ID), ids, _hashes);
}
}
35 changes: 0 additions & 35 deletions packages/evm/contracts/adapters/AMB/AMBHeaderReporter.sol

This file was deleted.

30 changes: 0 additions & 30 deletions packages/evm/contracts/adapters/AMB/AMBMessageRelayer.sol

This file was deleted.

40 changes: 40 additions & 0 deletions packages/evm/contracts/adapters/AMB/AMBReporter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

import { Reporter } from "../Reporter.sol";
import { AMBAdapter } from "./AMBAdapter.sol";
import { IOracleAdapter } from "../../interfaces/IOracleAdapter.sol";
import { IAMB } from "./IAMB.sol";

contract AMBReporter is Reporter {
string public constant PROVIDER = "amb";

address public immutable AMB;
uint256 public immutable GAS;
uint256 public immutable TO_CHAIN_ID;

error InvalidToChainId(uint256 chainId, uint256 expectedChainId);

constructor(
address headerStorage,
address yaho,
address amb,
uint256 toChainId,
uint256 gas
) Reporter(headerStorage, yaho) {
AMB = amb;
TO_CHAIN_ID = toChainId;
GAS = gas;
}

function _dispatch(
uint256 toChainId,
address adapter,
uint256[] memory ids,
bytes32[] memory hashes
) internal override returns (bytes32) {
if (toChainId != TO_CHAIN_ID) revert InvalidToChainId(toChainId, TO_CHAIN_ID);
bytes memory payload = abi.encodeCall(AMBAdapter.storeHashes, (ids, hashes));
return IAMB(AMB).requireToPassMessage(adapter, payload, GAS);
}
}
47 changes: 25 additions & 22 deletions packages/evm/contracts/adapters/Axelar/AxelarAdapter.sol
Original file line number Diff line number Diff line change
@@ -1,44 +1,47 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { AxelarExecutable } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import { HeaderOracleAdapter } from "../HeaderOracleAdapter.sol";
import { BlockHashOracleAdapter } from "../BlockHashOracleAdapter.sol";

contract AxelarAdapter is HeaderOracleAdapter, AxelarExecutable {
contract AxelarAdapter is BlockHashOracleAdapter, Ownable, AxelarExecutable {
string public constant PROVIDER = "axelar";
string public AXELAR_REPORTER_CHAIN; // Immutable
bytes32 public immutable AXELAR_REPORTER_CHAIN_HASH;
string public AXELAR_REPORTER_ADDRESS; // Immutable
bytes32 public immutable AXELAR_REPORTER_ADDRESS_HASH;

mapping(bytes32 => bytes32) public enabledReporters;
mapping(bytes32 => uint256) public chainIds;

error UnauthorizedAxelarReceive();
error ExecutionWithTokenNotSupported();

constructor(
uint256 reporterChain,
address reporterAddress,
address axelarGateway,
string memory axelarReporterChain,
string memory axelarReporterAddress
) HeaderOracleAdapter(reporterChain, reporterAddress) AxelarExecutable(axelarGateway) {
AXELAR_REPORTER_CHAIN = axelarReporterChain;
AXELAR_REPORTER_CHAIN_HASH = keccak256(bytes(axelarReporterChain));
AXELAR_REPORTER_ADDRESS = axelarReporterAddress;
AXELAR_REPORTER_ADDRESS_HASH = keccak256(bytes(axelarReporterAddress));
event ReporterSet(uint256 indexed chainId, string name, string indexed reporter);

constructor(address axelarGateway) AxelarExecutable(axelarGateway) {}

function setReporterByChain(
uint256 chainId,
string calldata chainName,
string calldata reporter
) external onlyOwner {
bytes32 chainNameHash = keccak256(bytes(chainName));
enabledReporters[chainNameHash] = keccak256(bytes(reporter));
chainIds[chainNameHash] = chainId;
emit ReporterSet(chainId, chainName, reporter);
}

function _execute(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) internal override {
if (
keccak256(bytes(sourceChain)) != AXELAR_REPORTER_CHAIN_HASH ||
keccak256(bytes(sourceAddress)) != AXELAR_REPORTER_ADDRESS_HASH
) {
bytes32 chainNameHash = keccak256(bytes(sourceChain));
bytes32 expectedSourceAddressHash = enabledReporters[chainNameHash];
uint256 sourceChainId = chainIds[chainNameHash];
if (expectedSourceAddressHash != keccak256(bytes(sourceAddress)) || sourceChainId == 0) {
revert UnauthorizedAxelarReceive();
}
_receivePayload(payload);
(uint256[] memory ids, bytes32[] memory hashes) = abi.decode(payload, (uint256[], bytes32[]));
_storeHashes(sourceChainId, ids, hashes);
}

function _executeWithToken(
Expand Down
19 changes: 0 additions & 19 deletions packages/evm/contracts/adapters/Axelar/AxelarHeaderReporter.sol

This file was deleted.

19 changes: 0 additions & 19 deletions packages/evm/contracts/adapters/Axelar/AxelarMessageRelay.sol

This file was deleted.

43 changes: 35 additions & 8 deletions packages/evm/contracts/adapters/Axelar/AxelarReporter.sol
Original file line number Diff line number Diff line change
@@ -1,37 +1,64 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IAxelarGateway } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol";
import { IAxelarGasService } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { Reporter } from "../Reporter.sol";

abstract contract AxelarReporter {
contract AxelarReporter is Reporter, Ownable {
using Strings for uint256;

string public constant PROVIDER = "axelar";
bytes32 private constant NULL_STRING = keccak256("");
IAxelarGateway public immutable AXELAR_GATEWAY;
IAxelarGasService public immutable AXELAR_GAS_SERVICE;
string public AXELAR_ADAPTER_CHAIN; // Immutable

constructor(address axelarGateway, address axelarGasService, string memory axelarAdapterChain) {
mapping(uint256 => string) public chainNames;

error ChainIdNotSupported(uint256 chainId);

event ChainNameSet(uint256 indexed chainId, string indexed chainName);

constructor(
address headerStorage,
address yaho,
address axelarGateway,
address axelarGasService
) Reporter(headerStorage, yaho) {
AXELAR_GATEWAY = IAxelarGateway(axelarGateway);
AXELAR_GAS_SERVICE = IAxelarGasService(axelarGasService);
AXELAR_ADAPTER_CHAIN = axelarAdapterChain;
}

function _axelarSend(bytes memory payload, address adapter) internal {
function setChainNameByChainId(uint256 chainId, string calldata chainName) external onlyOwner {
chainNames[chainId] = chainName;
emit ChainNameSet(chainId, chainName);
}

function _dispatch(
uint256 toChainId,
address adapter,
uint256[] memory ids,
bytes32[] memory hashes
) internal override returns (bytes32) {
string memory chainName = chainNames[toChainId];
if (keccak256(abi.encode(chainName)) == NULL_STRING) revert ChainIdNotSupported(toChainId);

string memory sAdapter = uint256(uint160(adapter)).toHexString(20);
bytes memory payload = abi.encode(ids, hashes);

if (msg.value > 0) {
AXELAR_GAS_SERVICE.payNativeGasForContractCall{ value: msg.value }(
address(this),
AXELAR_ADAPTER_CHAIN,
chainName,
sAdapter,
payload,
msg.sender
);
}

AXELAR_GATEWAY.callContract(AXELAR_ADAPTER_CHAIN, sAdapter, payload);
AXELAR_GATEWAY.callContract(chainName, sAdapter, payload);
return bytes32(0);
}
}
11 changes: 4 additions & 7 deletions packages/evm/contracts/adapters/BlockHashOracleAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@
pragma solidity ^0.8.17;

import { RLPReader } from "solidity-rlp/contracts/RLPReader.sol";

import { OracleAdapter } from "./OracleAdapter.sol";
import { IBlockHashOracleAdapter } from "../interfaces/IBlockHashOracleAdapter.sol";

abstract contract BlockHashOracleAdapter is OracleAdapter {
abstract contract BlockHashOracleAdapter is IBlockHashOracleAdapter, OracleAdapter {
using RLPReader for RLPReader.RLPItem;

/// @dev Proves and stores valid ancestral block hashes for a given chain ID.
/// @param chainId The ID of the chain to prove block hashes for.
/// @param blockHeaders The RLP encoded block headers to prove the hashes for.
/// @notice Block headers should be ordered by descending block number and should start with a known block header.
/// @inheritdoc IBlockHashOracleAdapter
function proveAncestralBlockHashes(uint256 chainId, bytes[] memory blockHeaders) external {
for (uint256 i = 0; i < blockHeaders.length; i++) {
RLPReader.RLPItem memory blockHeaderRLP = RLPReader.toRlpItem(blockHeaders[i]);
Expand All @@ -28,7 +25,7 @@ abstract contract BlockHashOracleAdapter is OracleAdapter {
uint256 blockNumber = uint256(blockHeaderContent[8].toUint());

bytes32 reportedBlockHash = keccak256(blockHeaders[i]);
bytes32 storedBlockHash = hashes[chainId][blockNumber];
bytes32 storedBlockHash = getHashFromOracle(chainId, blockNumber);

if (reportedBlockHash != storedBlockHash)
revert ConflictingBlockHeader(blockNumber, reportedBlockHash, storedBlockHash);
Expand Down
Loading

0 comments on commit 6836e2b

Please sign in to comment.