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

Hyperlane Teller #35

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion deployment-config/chains/11155111.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "Ethereum Sepolia",
"balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8",
"lzEndpoint": "0x6EDCE65403992e310A62460808c4b910D972f10f"
"lzEndpoint": "0x6EDCE65403992e310A62460808c4b910D972f10f",
"mailbox": "0xfFAEF09B3cd11D9b20d1a19bECca54EEC2884766"
}
6 changes: 6 additions & 0 deletions deployment-config/chains/11155420.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "Optimism Sepolia",
"balancerVault": "0x0000000000000000000000000000000000000000",
"lzEndpoint": "0x0000000000000000000000000000000000000000",
"mailbox": "0x6966b0E55883d49BFB24539356a2f8A673E02039"
}
46 changes: 46 additions & 0 deletions deployment-config/eth-sepolia-hyperlane-L1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"base": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9",
"protocolAdmin": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"boringVaultAndBaseDecimals": "18",
"boringVault": {
"boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000001c",
"boringVaultName": "Nucleus Vault",
"boringVaultSymbol": "NV",
"address": "0x0000000000000000000000000000000000000000"
},
"manager": {
"managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000001c",
"address": "0x0000000000000000000000000000000000000000"
},
"accountant": {
"accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000001c",
"payoutAddress": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"allowedExchangeRateChangeUpper": "10003",
"allowedExchangeRateChangeLower": "10000",
"minimumUpdateDelayInSeconds": "3600",
"managementFee": "2000",
"address": "0x0000000000000000000000000000000000000000"
},
"teller": {
"tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000001c",
"maxGasForPeer": 100000,
"minGasForPeer": 0,
"peerEid": 0,
"peerDomainId": 11155420,
"tellerContractName": "MultiChainHyperlaneTellerWithMultiAssetSupport",
"assets": [
],
"address": "0x0000000000000000000000000000000000000000"
},
"rolesAuthority": {
"rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000001c",
"strategist": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"exchangeRateBot": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"pauser": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"address": "0x0000000000000000000000000000000000000000"
},
"decoder": {
"decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000001c",
"address": "0x0000000000000000000000000000000000000000"
}
}
46 changes: 46 additions & 0 deletions deployment-config/op-sepolia-hyperlane-L2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"base": "0x1BDD24840e119DC2602dCC587Dd182812427A5Cc",
"protocolAdmin": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"boringVaultAndBaseDecimals": "18",
"boringVault": {
"boringVaultSalt": "0x1ddd634c506ad203da17ff00000000000000000000000000000000000000001c",
"boringVaultName": "Nucleus Vault",
"boringVaultSymbol": "NV",
"address": "0x0000000000000000000000000000000000000000"
},
"manager": {
"managerSalt": "0x30432d4b4ec00003b4a25000000000000000000000000000000000000000001c",
"address": "0x0000000000000000000000000000000000000000"
},
"accountant": {
"accountantSalt": "0x6a184dbea6f3cc0318679f00000000000000000000000000000000000000001c",
"payoutAddress": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"allowedExchangeRateChangeUpper": "10003",
"allowedExchangeRateChangeLower": "10000",
"minimumUpdateDelayInSeconds": "3600",
"managementFee": "2000",
"address": "0x0000000000000000000000000000000000000000"
},
"teller": {
"tellerSalt": "0x51f8968749a56d01202c9100000000000000000000000000000000000000001c",
"maxGasForPeer": 100000,
"minGasForPeer": 0,
"peerEid": 0,
"peerDomainId": 11155111,
"tellerContractName": "MultiChainHyperlaneTellerWithMultiAssetSupport",
"assets": [
],
"address": "0x0000000000000000000000000000000000000000"
},
"rolesAuthority": {
"rolesAuthoritySalt": "0x66bbc3b3b3000b01466a3a00000000000000000000000000000000000000001c",
"strategist": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"exchangeRateBot": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"pauser": "0x94544835Cf97c631f101c5f538787fE14E2E04f6",
"address": "0x0000000000000000000000000000000000000000"
},
"decoder": {
"decoderSalt": "0x48b53893da2e0b0248268c00000000000000000000000000000000000000001c",
"address": "0x0000000000000000000000000000000000000000"
}
}
27 changes: 20 additions & 7 deletions script/ConfigReader.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ library ConfigReader {
uint64 maxGasForPeer;
uint64 minGasForPeer;
address lzEndpoint;
address mailbox;
uint32 peerDomainId;
bytes32 rolesAuthoritySalt;
address manager;
address teller;
Expand Down Expand Up @@ -88,13 +90,21 @@ library ConfigReader {
config.minGasForPeer = uint64(_config.readUint(".teller.minGasForPeer"));
config.tellerContractName = _config.readString(".teller.tellerContractName");
config.assets = _config.readAddressArray(".teller.assets");
config.peerEid = uint32(_config.readUint(".teller.peerEid"));

config.requiredDvns = _config.readAddressArray(".teller.dvnIfNoDefault.required");
config.optionalDvns = _config.readAddressArray(".teller.dvnIfNoDefault.optional");
config.dvnBlockConfirmationsRequired =
uint64(_config.readUint(".teller.dvnIfNoDefault.blockConfirmationsRequiredIfNoDefault"));
config.optionalDvnThreshold = uint8(_config.readUint(".teller.dvnIfNoDefault.optionalThreshold"));
// layerzero
if (compareStrings(config.tellerContractName, "MultiChainLayerZeroTellerWithMultiAssetSupport")) {
config.lzEndpoint = _chainConfig.readAddress(".lzEndpoint");

config.peerEid = uint32(_config.readUint(".teller.peerEid"));
config.requiredDvns = _config.readAddressArray(".teller.dvnIfNoDefault.required");
config.optionalDvns = _config.readAddressArray(".teller.dvnIfNoDefault.optional");
config.dvnBlockConfirmationsRequired =
uint64(_config.readUint(".teller.dvnIfNoDefault.blockConfirmationsRequiredIfNoDefault"));
config.optionalDvnThreshold = uint8(_config.readUint(".teller.dvnIfNoDefault.optionalThreshold"));
} else if (compareStrings(config.tellerContractName, "MultiChainHyperlaneTellerWithMultiAssetSupport")) {
config.mailbox = _chainConfig.readAddress(".mailbox");
config.peerDomainId = uint32(_config.readUint(".teller.peerDomainId"));
}

// Reading from the 'rolesAuthority' section
config.rolesAuthority = _config.readAddress(".rolesAuthority.address");
Expand All @@ -109,8 +119,11 @@ library ConfigReader {

// Reading from the 'chainConfig' section
config.balancerVault = _chainConfig.readAddress(".balancerVault");
config.lzEndpoint = _chainConfig.readAddress(".lzEndpoint");

return config;
}

function compareStrings(string memory a, string memory b) internal pure returns (bool) {
return (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)));
}
}
3 changes: 3 additions & 0 deletions script/deploy/deployAll.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { DeployCrossChainOPTellerWithMultiAssetSupport } from
"./single/05a_DeployCrossChainOPTellerWithMultiAssetSupport.s.sol";
import { DeployMultiChainLayerZeroTellerWithMultiAssetSupport } from
"./single/05b_DeployMultiChainLayerZeroTellerWithMultiAssetSupport.s.sol";
import { DeployMultiChainHyperlaneTeller } from "./single/05c_DeployMultiChainHyperlaneTeller.s.sol";
import { DeployRolesAuthority } from "./single/06_DeployRolesAuthority.s.sol";
import { TellerSetup } from "./single/07_TellerSetup.s.sol";
import { SetAuthorityAndTransferOwnerships } from "./single/08_SetAuthorityAndTransferOwnerships.s.sol";
Expand Down Expand Up @@ -102,6 +103,8 @@ contract DeployAll is BaseScript {
teller = new DeployCrossChainOPTellerWithMultiAssetSupport().deploy(config);
} else if (compareStrings(config.tellerContractName, "MultiChainLayerZeroTellerWithMultiAssetSupport")) {
teller = new DeployMultiChainLayerZeroTellerWithMultiAssetSupport().deploy(config);
} else if (compareStrings(config.tellerContractName, "MultiChainHyperlaneTellerWithMultiAssetSupport")) {
teller = new DeployMultiChainHyperlaneTeller().deploy(config);
} else if (compareStrings(config.tellerContractName, "TellerWithMultiAssetSupport")) {
teller = new DeployTellerWithMultiAssetSupport().deploy(config);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract DeployAccountantWithRateProviders is BaseScript {
require(config.base != address(0), "base address must not be zero");
require(config.allowedExchangeRateChangeUpper > 1e4, "allowedExchangeRateChangeUpper");
require(config.allowedExchangeRateChangeUpper <= 1.003e4, "allowedExchangeRateChangeUpper upper bound");
require(config.allowedExchangeRateChangeLower < 1e4, "allowedExchangeRateChangeLower");
require(config.allowedExchangeRateChangeLower <= 1e4, "allowedExchangeRateChangeLower");
require(config.allowedExchangeRateChangeLower >= 0.997e4, "allowedExchangeRateChangeLower lower bound");
require(config.minimumUpdateDelayInSeconds >= 3600, "minimumUpdateDelayInSeconds");
require(config.managementFee < 1e4, "managementFee");
Expand Down
54 changes: 54 additions & 0 deletions script/deploy/single/05c_DeployMultiChainHyperlaneTeller.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.21;

import { AccountantWithRateProviders } from "./../../../src/base/Roles/AccountantWithRateProviders.sol";
import { MultiChainHyperlaneTellerWithMultiAssetSupport } from
"./../../../src/base/Roles/CrossChain/MultiChainHyperlaneTellerWithMultiAssetSupport.sol";
import { IMailbox } from "./../../../src/interfaces/hyperlane/IMailbox.sol";
import { BaseScript } from "./../../Base.s.sol";
import { stdJson as StdJson } from "@forge-std/StdJson.sol";
import { ConfigReader } from "../../ConfigReader.s.sol";
import { console2 } from "@forge-std/console2.sol";

contract DeployMultiChainHyperlaneTeller is BaseScript {
using StdJson for string;

function run() public returns (address teller) {
return deploy(getConfig());
}

function deploy(ConfigReader.Config memory config) public override broadcast returns (address) {
// Require config Values
require(config.boringVault.code.length != 0, "boringVault must have code");
require(config.accountant.code.length != 0, "accountant must have code");
require(config.tellerSalt != bytes32(0), "tellerSalt");
require(config.boringVault != address(0), "boringVault");
require(config.accountant != address(0), "accountant");

// Create Contract
bytes memory creationCode = type(MultiChainHyperlaneTellerWithMultiAssetSupport).creationCode;
MultiChainHyperlaneTellerWithMultiAssetSupport teller = MultiChainHyperlaneTellerWithMultiAssetSupport(
CREATEX.deployCreate3(
config.tellerSalt,
abi.encodePacked(
creationCode, abi.encode(broadcaster, config.boringVault, config.accountant, config.mailbox)
)
)
);

teller.addChain(config.peerDomainId, true, true, address(teller), config.maxGasForPeer, config.minGasForPeer);

IMailbox mailbox = teller.mailbox();

// Post Deploy Checks
require(teller.shareLockPeriod() == 0, "share lock period must be zero");
require(teller.isPaused() == false, "the teller must not be paused");
require(
AccountantWithRateProviders(teller.accountant()).vault() == teller.vault(),
"the accountant vault must be the teller vault"
);
require(address(mailbox) == config.mailbox, "mailbox must be set");

return address(teller);
}
}
141 changes: 141 additions & 0 deletions src/base/Roles/CrossChain/Hyperlane/StandardHookMetadata.sol
Copy link
Collaborator

Choose a reason for hiding this comment

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

Considering this is a library maybe move this to src/helpers if it's not able to be forge installed. Is there any changes made from Hyperlane's implementation?

Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/

/**
* Format of metadata:
*
* [0:2] variant
* [2:34] msg.value
* [34:66] Gas limit for message (IGP)
* [66:86] Refund address for message (IGP)
* [86:] Custom metadata
*/
library StandardHookMetadata {
struct Metadata {
uint16 variant;
uint256 msgValue;
uint256 gasLimit;
address refundAddress;
}

uint8 private constant VARIANT_OFFSET = 0;
uint8 private constant MSG_VALUE_OFFSET = 2;
uint8 private constant GAS_LIMIT_OFFSET = 34;
uint8 private constant REFUND_ADDRESS_OFFSET = 66;
uint256 private constant MIN_METADATA_LENGTH = 86;

uint16 public constant VARIANT = 1;

/**
* @notice Returns the variant of the metadata.
* @param _metadata ABI encoded standard hook metadata.
* @return variant of the metadata as uint8.
*/
function variant(bytes calldata _metadata) internal pure returns (uint16) {
if (_metadata.length < VARIANT_OFFSET + 2) return 0;
return uint16(bytes2(_metadata[VARIANT_OFFSET:VARIANT_OFFSET + 2]));
}

/**
* @notice Returns the specified value for the message.
* @param _metadata ABI encoded standard hook metadata.
* @param _default Default fallback value.
* @return Value for the message as uint256.
*/
function msgValue(bytes calldata _metadata, uint256 _default) internal pure returns (uint256) {
if (_metadata.length < MSG_VALUE_OFFSET + 32) return _default;
return uint256(bytes32(_metadata[MSG_VALUE_OFFSET:MSG_VALUE_OFFSET + 32]));
}

/**
* @notice Returns the specified gas limit for the message.
* @param _metadata ABI encoded standard hook metadata.
* @param _default Default fallback gas limit.
* @return Gas limit for the message as uint256.
*/
function gasLimit(bytes calldata _metadata, uint256 _default) internal pure returns (uint256) {
if (_metadata.length < GAS_LIMIT_OFFSET + 32) return _default;
return uint256(bytes32(_metadata[GAS_LIMIT_OFFSET:GAS_LIMIT_OFFSET + 32]));
}

/**
* @notice Returns the specified refund address for the message.
* @param _metadata ABI encoded standard hook metadata.
* @param _default Default fallback refund address.
* @return Refund address for the message as address.
*/
function refundAddress(bytes calldata _metadata, address _default) internal pure returns (address) {
if (_metadata.length < REFUND_ADDRESS_OFFSET + 20) return _default;
return address(bytes20(_metadata[REFUND_ADDRESS_OFFSET:REFUND_ADDRESS_OFFSET + 20]));
}

/**
* @notice Returns any custom metadata.
* @param _metadata ABI encoded standard hook metadata.
* @return Custom metadata.
*/
function getCustomMetadata(bytes calldata _metadata) internal pure returns (bytes calldata) {
if (_metadata.length < MIN_METADATA_LENGTH) return _metadata[0:0];
return _metadata[MIN_METADATA_LENGTH:];
}

/**
* @notice Formats the specified gas limit and refund address into standard hook metadata.
* @param _msgValue msg.value for the message.
* @param _gasLimit Gas limit for the message.
* @param _refundAddress Refund address for the message.
* @param _customMetadata Additional metadata to include in the standard hook metadata.
* @return ABI encoded standard hook metadata.
*/
function formatMetadata(
uint256 _msgValue,
uint256 _gasLimit,
address _refundAddress,
bytes memory _customMetadata
)
internal
pure
returns (bytes memory)
{
return abi.encodePacked(VARIANT, _msgValue, _gasLimit, _refundAddress, _customMetadata);
}

/**
* @notice Formats the specified gas limit and refund address into standard hook metadata.
* @param _msgValue msg.value for the message.
* @return ABI encoded standard hook metadata.
*/
function overrideMsgValue(uint256 _msgValue) internal view returns (bytes memory) {
return formatMetadata(_msgValue, uint256(0), msg.sender, "");
}

/**
* @notice Formats the specified gas limit and refund address into standard hook metadata.
* @param _gasLimit Gas limit for the message.
* @return ABI encoded standard hook metadata.
*/
function overrideGasLimit(uint256 _gasLimit) internal view returns (bytes memory) {
return formatMetadata(uint256(0), _gasLimit, msg.sender, "");
}

/**
* @notice Formats the specified refund address into standard hook metadata.
* @param _refundAddress Refund address for the message.
* @return ABI encoded standard hook metadata.
*/
function overrideRefundAddress(address _refundAddress) internal pure returns (bytes memory) {
return formatMetadata(uint256(0), uint256(0), _refundAddress, "");
}
}
Loading
Loading