commit
f3e015b167
@ -1,7 +0,0 @@ |
|||||||
--- |
|
||||||
"@hyperlane-xyz/cli": patch |
|
||||||
"@hyperlane-xyz/helloworld": patch |
|
||||||
"@hyperlane-xyz/infra": patch |
|
||||||
--- |
|
||||||
|
|
||||||
fix: minor change was breaking in registry export |
|
@ -1,5 +0,0 @@ |
|||||||
--- |
|
||||||
'@hyperlane-xyz/cli': minor |
|
||||||
--- |
|
||||||
|
|
||||||
Add hyperlane validator address command to retrieve validator address from AWS |
|
@ -1,7 +0,0 @@ |
|||||||
--- |
|
||||||
'@hyperlane-xyz/infra': minor |
|
||||||
'@hyperlane-xyz/cli': minor |
|
||||||
'@hyperlane-xyz/sdk': minor |
|
||||||
--- |
|
||||||
|
|
||||||
Implement multi collateral warp routes |
|
@ -1,7 +0,0 @@ |
|||||||
--- |
|
||||||
'@hyperlane-xyz/cli': minor |
|
||||||
'@hyperlane-xyz/sdk': minor |
|
||||||
'@hyperlane-xyz/core': minor |
|
||||||
--- |
|
||||||
|
|
||||||
Support xERC20 and xERC20 Lockbox in SDK and CLI |
|
@ -0,0 +1,5 @@ |
|||||||
|
--- |
||||||
|
"@hyperlane-xyz/core": patch |
||||||
|
--- |
||||||
|
|
||||||
|
fix: make XERC20 and XERC20 Lockbox proxy-able |
@ -1,7 +0,0 @@ |
|||||||
--- |
|
||||||
'@hyperlane-xyz/infra': minor |
|
||||||
'@hyperlane-xyz/utils': minor |
|
||||||
'@hyperlane-xyz/sdk': minor |
|
||||||
--- |
|
||||||
|
|
||||||
Implement metadata builder fetching from message |
|
@ -0,0 +1,109 @@ |
|||||||
|
name: test |
||||||
|
|
||||||
|
on: |
||||||
|
push: |
||||||
|
branches: [main] |
||||||
|
pull_request: |
||||||
|
branches: |
||||||
|
- '*' |
||||||
|
paths: |
||||||
|
- '*.md' |
||||||
|
- '!**/*' |
||||||
|
merge_group: |
||||||
|
|
||||||
|
concurrency: |
||||||
|
group: e2e-${{ github.ref }} |
||||||
|
cancel-in-progress: ${{ github.ref_name != 'main' }} |
||||||
|
|
||||||
|
jobs: |
||||||
|
yarn-install: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "yarn-install job passed" |
||||||
|
|
||||||
|
yarn-build: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "yarn-build job passed" |
||||||
|
|
||||||
|
checkout-registry: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "checkout-registry job passed" |
||||||
|
|
||||||
|
lint-prettier: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "lint-prettier job passed" |
||||||
|
|
||||||
|
yarn-test: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "yarn-test job passed" |
||||||
|
|
||||||
|
agent-configs: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
strategy: |
||||||
|
fail-fast: false |
||||||
|
matrix: |
||||||
|
environment: [mainnet3, testnet4] |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "agent-configs job passed" |
||||||
|
|
||||||
|
e2e-matrix: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.base_ref == 'main') || github.event_name == 'merge_group' |
||||||
|
strategy: |
||||||
|
matrix: |
||||||
|
e2e-type: [cosmwasm, non-cosmwasm] |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "e2e-matrix job passed" |
||||||
|
|
||||||
|
e2e: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
if: always() |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "e2e job passed" |
||||||
|
|
||||||
|
cli-e2e: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.base_ref == 'main') || github.event_name == 'merge_group' |
||||||
|
strategy: |
||||||
|
matrix: |
||||||
|
include: |
||||||
|
- test-type: preset_hook_enabled |
||||||
|
- test-type: configure_hook_enabled |
||||||
|
- test-type: pi_with_core_chain |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "cli-e2e job passed" |
||||||
|
|
||||||
|
env-test: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
strategy: |
||||||
|
fail-fast: false |
||||||
|
matrix: |
||||||
|
environment: [mainnet3] |
||||||
|
chain: [ethereum, arbitrum, optimism, inevm, viction] |
||||||
|
module: [core, igp] |
||||||
|
include: |
||||||
|
- environment: testnet4 |
||||||
|
chain: sepolia |
||||||
|
module: core |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "env-test job passed" |
||||||
|
|
||||||
|
coverage: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- name: Instant pass |
||||||
|
run: echo "coverage job passed" |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"opRetro": { |
||||||
|
"projectId": "0xa47182d330bd0c5c69b1418462f3f742099138f09bff057189cdd19676a6acd1" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
mod merkle_tree; |
||||||
|
mod msg; |
||||||
|
mod processor; |
||||||
|
mod prover; |
||||||
|
mod relayer; |
||||||
|
mod server; |
||||||
|
mod settings; |
||||||
|
|
||||||
|
pub use msg::GAS_EXPENDITURE_LOG_MESSAGE; |
||||||
|
pub use relayer::*; |
@ -1,11 +1,8 @@ |
|||||||
pub use {interchain_gas::*, mailbox::*, merkle_tree_hook::*, validator_announce::*}; |
pub use {interchain_gas::*, mailbox::*, merkle_tree_hook::*, validator_announce::*}; |
||||||
|
|
||||||
mod interchain_gas; |
mod interchain_gas; |
||||||
|
|
||||||
mod mailbox; |
mod mailbox; |
||||||
|
|
||||||
mod merkle_tree_hook; |
mod merkle_tree_hook; |
||||||
|
|
||||||
mod multicall; |
mod multicall; |
||||||
|
mod utils; |
||||||
mod validator_announce; |
mod validator_announce; |
||||||
|
@ -0,0 +1,48 @@ |
|||||||
|
use std::sync::Arc; |
||||||
|
|
||||||
|
use ethers::{ |
||||||
|
abi::RawLog, |
||||||
|
providers::Middleware, |
||||||
|
types::{H160 as EthersH160, H256 as EthersH256}, |
||||||
|
}; |
||||||
|
use ethers_contract::{ContractError, EthEvent, LogMeta as EthersLogMeta}; |
||||||
|
use hyperlane_core::{ChainResult, LogMeta, H512}; |
||||||
|
use tracing::warn; |
||||||
|
|
||||||
|
pub async fn fetch_raw_logs_and_log_meta<T: EthEvent, M>( |
||||||
|
tx_hash: H512, |
||||||
|
provider: Arc<M>, |
||||||
|
contract_address: EthersH160, |
||||||
|
) -> ChainResult<Vec<(T, LogMeta)>> |
||||||
|
where |
||||||
|
M: Middleware + 'static, |
||||||
|
{ |
||||||
|
let ethers_tx_hash: EthersH256 = tx_hash.into(); |
||||||
|
let receipt = provider |
||||||
|
.get_transaction_receipt(ethers_tx_hash) |
||||||
|
.await |
||||||
|
.map_err(|err| ContractError::<M>::MiddlewareError(err))?; |
||||||
|
let Some(receipt) = receipt else { |
||||||
|
warn!(%tx_hash, "No receipt found for tx hash"); |
||||||
|
return Ok(vec![]); |
||||||
|
}; |
||||||
|
|
||||||
|
let logs: Vec<(T, LogMeta)> = receipt |
||||||
|
.logs |
||||||
|
.into_iter() |
||||||
|
.filter_map(|log| { |
||||||
|
// Filter out logs that aren't emitted by this contract
|
||||||
|
if log.address != contract_address { |
||||||
|
return None; |
||||||
|
} |
||||||
|
let raw_log = RawLog { |
||||||
|
topics: log.topics.clone(), |
||||||
|
data: log.data.to_vec(), |
||||||
|
}; |
||||||
|
let log_meta: EthersLogMeta = (&log).into(); |
||||||
|
let event_filter = T::decode_log(&raw_log).ok(); |
||||||
|
event_filter.map(|log| (log, log_meta.into())) |
||||||
|
}) |
||||||
|
.collect(); |
||||||
|
Ok(logs) |
||||||
|
} |
@ -1,50 +0,0 @@ |
|||||||
use derive_new::new; |
|
||||||
use tokio::sync::broadcast::{Receiver, Sender}; |
|
||||||
|
|
||||||
/// Multi-producer, multi-consumer channel
|
|
||||||
pub struct MpmcChannel<T> { |
|
||||||
sender: Sender<T>, |
|
||||||
receiver: MpmcReceiver<T>, |
|
||||||
} |
|
||||||
|
|
||||||
impl<T: Clone> MpmcChannel<T> { |
|
||||||
/// Creates a new `MpmcChannel` with the specified capacity.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `capacity` - The maximum number of messages that can be buffered in the channel.
|
|
||||||
pub fn new(capacity: usize) -> Self { |
|
||||||
let (sender, receiver) = tokio::sync::broadcast::channel(capacity); |
|
||||||
Self { |
|
||||||
sender: sender.clone(), |
|
||||||
receiver: MpmcReceiver::new(sender, receiver), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Returns a clone of the sender end of the channel.
|
|
||||||
pub fn sender(&self) -> Sender<T> { |
|
||||||
self.sender.clone() |
|
||||||
} |
|
||||||
|
|
||||||
/// Returns a clone of the receiver end of the channel.
|
|
||||||
pub fn receiver(&self) -> MpmcReceiver<T> { |
|
||||||
self.receiver.clone() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Clonable receiving end of a multi-producer, multi-consumer channel
|
|
||||||
#[derive(Debug, new)] |
|
||||||
pub struct MpmcReceiver<T> { |
|
||||||
sender: Sender<T>, |
|
||||||
/// The receiving end of the channel.
|
|
||||||
pub receiver: Receiver<T>, |
|
||||||
} |
|
||||||
|
|
||||||
impl<T> Clone for MpmcReceiver<T> { |
|
||||||
fn clone(&self) -> Self { |
|
||||||
Self { |
|
||||||
sender: self.sender.clone(), |
|
||||||
receiver: self.sender.subscribe(), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1 +1 @@ |
|||||||
Subproject commit e8a047e3f40f13fa37af6fe14e6e06283d9a060e |
Subproject commit 52715a217dc51d0de15877878ab8213f6cbbbab5 |
@ -0,0 +1,4 @@ |
|||||||
|
export ROUTER_ADDRESS=0xA34ceDf9068C5deE726C67A4e1DCfCc2D6E2A7fD |
||||||
|
export ERC20_ADDRESS=0x2416092f143378750bb29b79eD961ab195CcEea5 |
||||||
|
export XERC20_ADDRESS=0x2416092f143378750bb29b79eD961ab195CcEea5 |
||||||
|
export RPC_URL="https://rpc.blast.io" |
@ -0,0 +1,5 @@ |
|||||||
|
export ROUTER_ADDRESS=0x8dfbEA2582F41c8C4Eb25252BbA392fd3c09449A |
||||||
|
export ADMIN_ADDRESS=0xa5B0D537CeBE97f087Dc5FE5732d70719caaEc1D |
||||||
|
export ERC20_ADDRESS=0xbf5495Efe5DB9ce00f80364C8B423567e58d2110 |
||||||
|
export XERC20_ADDRESS=0x2416092f143378750bb29b79eD961ab195CcEea5 |
||||||
|
export RPC_URL="https://eth.merkle.io" |
@ -0,0 +1,50 @@ |
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||||
|
pragma solidity >=0.8.0; |
||||||
|
|
||||||
|
import "forge-std/Script.sol"; |
||||||
|
|
||||||
|
import {AnvilRPC} from "test/AnvilRPC.sol"; |
||||||
|
import {TypeCasts} from "contracts/libs/TypeCasts.sol"; |
||||||
|
|
||||||
|
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; |
||||||
|
|
||||||
|
import {ProxyAdmin} from "contracts/upgrade/ProxyAdmin.sol"; |
||||||
|
|
||||||
|
import {HypXERC20Lockbox} from "contracts/token/extensions/HypXERC20Lockbox.sol"; |
||||||
|
import {IXERC20Lockbox} from "contracts/token/interfaces/IXERC20Lockbox.sol"; |
||||||
|
import {IXERC20} from "contracts/token/interfaces/IXERC20.sol"; |
||||||
|
import {IERC20} from "contracts/token/interfaces/IXERC20.sol"; |
||||||
|
|
||||||
|
// source .env.<CHAIN> |
||||||
|
// forge script ApproveLockbox.s.sol --broadcast --rpc-url localhost:XXXX |
||||||
|
contract ApproveLockbox is Script { |
||||||
|
address router = vm.envAddress("ROUTER_ADDRESS"); |
||||||
|
address admin = vm.envAddress("ADMIN_ADDRESS"); |
||||||
|
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); |
||||||
|
|
||||||
|
ITransparentUpgradeableProxy proxy = ITransparentUpgradeableProxy(router); |
||||||
|
HypXERC20Lockbox old = HypXERC20Lockbox(router); |
||||||
|
address lockbox = address(old.lockbox()); |
||||||
|
address mailbox = address(old.mailbox()); |
||||||
|
ProxyAdmin proxyAdmin = ProxyAdmin(admin); |
||||||
|
|
||||||
|
function run() external { |
||||||
|
assert(proxyAdmin.getProxyAdmin(proxy) == admin); |
||||||
|
|
||||||
|
vm.startBroadcast(deployerPrivateKey); |
||||||
|
HypXERC20Lockbox logic = new HypXERC20Lockbox(lockbox, mailbox); |
||||||
|
proxyAdmin.upgradeAndCall( |
||||||
|
proxy, |
||||||
|
address(logic), |
||||||
|
abi.encodeCall(HypXERC20Lockbox.approveLockbox, ()) |
||||||
|
); |
||||||
|
vm.stopBroadcast(); |
||||||
|
|
||||||
|
vm.expectRevert("Initializable: contract is already initialized"); |
||||||
|
HypXERC20Lockbox(address(proxy)).initialize( |
||||||
|
address(0), |
||||||
|
address(0), |
||||||
|
mailbox |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||||
|
pragma solidity >=0.8.0; |
||||||
|
|
||||||
|
import "forge-std/Script.sol"; |
||||||
|
|
||||||
|
import {AnvilRPC} from "test/AnvilRPC.sol"; |
||||||
|
|
||||||
|
import {IXERC20Lockbox} from "contracts/token/interfaces/IXERC20Lockbox.sol"; |
||||||
|
import {IXERC20} from "contracts/token/interfaces/IXERC20.sol"; |
||||||
|
import {IERC20} from "contracts/token/interfaces/IXERC20.sol"; |
||||||
|
|
||||||
|
// source .env.<CHAIN> |
||||||
|
// anvil --fork-url $RPC_URL --port XXXX |
||||||
|
// forge script GrantLimits.s.sol --broadcast --unlocked --rpc-url localhost:XXXX |
||||||
|
contract GrantLimits is Script { |
||||||
|
address tester = 0xa7ECcdb9Be08178f896c26b7BbD8C3D4E844d9Ba; |
||||||
|
uint256 amount = 1 gwei; |
||||||
|
|
||||||
|
address router = vm.envAddress("ROUTER_ADDRESS"); |
||||||
|
IERC20 erc20 = IERC20(vm.envAddress("ERC20_ADDRESS")); |
||||||
|
IXERC20 xerc20 = IXERC20(vm.envAddress("XERC20_ADDRESS")); |
||||||
|
|
||||||
|
function runFrom(address account) internal { |
||||||
|
AnvilRPC.setBalance(account, 1 ether); |
||||||
|
AnvilRPC.impersonateAccount(account); |
||||||
|
vm.broadcast(account); |
||||||
|
} |
||||||
|
|
||||||
|
function run() external { |
||||||
|
address owner = xerc20.owner(); |
||||||
|
runFrom(owner); |
||||||
|
xerc20.setLimits(router, amount, amount); |
||||||
|
|
||||||
|
runFrom(address(erc20)); |
||||||
|
erc20.transfer(tester, amount); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||||
|
pragma solidity >=0.8.0; |
||||||
|
|
||||||
|
import "forge-std/Script.sol"; |
||||||
|
|
||||||
|
import {IXERC20Lockbox} from "../../contracts/token/interfaces/IXERC20Lockbox.sol"; |
||||||
|
import {IXERC20} from "../../contracts/token/interfaces/IXERC20.sol"; |
||||||
|
import {IERC20} from "../../contracts/token/interfaces/IXERC20.sol"; |
||||||
|
import {HypXERC20Lockbox} from "../../contracts/token/extensions/HypXERC20Lockbox.sol"; |
||||||
|
import {HypERC20Collateral} from "../../contracts/token/HypERC20Collateral.sol"; |
||||||
|
import {HypXERC20} from "../../contracts/token/extensions/HypXERC20.sol"; |
||||||
|
import {TransparentUpgradeableProxy} from "../../contracts/upgrade/TransparentUpgradeableProxy.sol"; |
||||||
|
import {ProxyAdmin} from "../../contracts/upgrade/ProxyAdmin.sol"; |
||||||
|
|
||||||
|
import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; |
||||||
|
import {TokenMessage} from "../../contracts/token/libs/TokenMessage.sol"; |
||||||
|
|
||||||
|
contract ezETH is Script { |
||||||
|
using TypeCasts for address; |
||||||
|
|
||||||
|
string ETHEREUM_RPC_URL = vm.envString("ETHEREUM_RPC_URL"); |
||||||
|
string BLAST_RPC_URL = vm.envString("BLAST_RPC_URL"); |
||||||
|
|
||||||
|
uint256 ethereumFork; |
||||||
|
uint32 ethereumDomainId = 1; |
||||||
|
address ethereumMailbox = 0xc005dc82818d67AF737725bD4bf75435d065D239; |
||||||
|
address ethereumLockbox = 0xC8140dA31E6bCa19b287cC35531c2212763C2059; |
||||||
|
|
||||||
|
uint256 blastFork; |
||||||
|
uint32 blastDomainId = 81457; |
||||||
|
address blastXERC20 = 0x2416092f143378750bb29b79eD961ab195CcEea5; |
||||||
|
address blastMailbox = 0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7; |
||||||
|
|
||||||
|
uint256 amount = 100; |
||||||
|
|
||||||
|
function setUp() public { |
||||||
|
ethereumFork = vm.createFork(ETHEREUM_RPC_URL); |
||||||
|
blastFork = vm.createFork(BLAST_RPC_URL); |
||||||
|
} |
||||||
|
|
||||||
|
function run() external { |
||||||
|
address deployer = address(this); |
||||||
|
bytes32 recipient = deployer.addressToBytes32(); |
||||||
|
bytes memory tokenMessage = TokenMessage.format(recipient, amount, ""); |
||||||
|
vm.selectFork(ethereumFork); |
||||||
|
HypXERC20Lockbox hypXERC20Lockbox = new HypXERC20Lockbox( |
||||||
|
ethereumLockbox, |
||||||
|
ethereumMailbox |
||||||
|
); |
||||||
|
ProxyAdmin ethAdmin = new ProxyAdmin(); |
||||||
|
TransparentUpgradeableProxy ethProxy = new TransparentUpgradeableProxy( |
||||||
|
address(hypXERC20Lockbox), |
||||||
|
address(ethAdmin), |
||||||
|
abi.encodeCall( |
||||||
|
HypXERC20Lockbox.initialize, |
||||||
|
(address(0), address(0), deployer) |
||||||
|
) |
||||||
|
); |
||||||
|
hypXERC20Lockbox = HypXERC20Lockbox(address(ethProxy)); |
||||||
|
|
||||||
|
vm.selectFork(blastFork); |
||||||
|
HypXERC20 hypXERC20 = new HypXERC20(blastXERC20, blastMailbox); |
||||||
|
ProxyAdmin blastAdmin = new ProxyAdmin(); |
||||||
|
TransparentUpgradeableProxy blastProxy = new TransparentUpgradeableProxy( |
||||||
|
address(hypXERC20), |
||||||
|
address(blastAdmin), |
||||||
|
abi.encodeCall( |
||||||
|
HypERC20Collateral.initialize, |
||||||
|
(address(0), address(0), deployer) |
||||||
|
) |
||||||
|
); |
||||||
|
hypXERC20 = HypXERC20(address(blastProxy)); |
||||||
|
hypXERC20.enrollRemoteRouter( |
||||||
|
ethereumDomainId, |
||||||
|
address(hypXERC20Lockbox).addressToBytes32() |
||||||
|
); |
||||||
|
|
||||||
|
// grant `amount` mint and burn limit to warp route |
||||||
|
vm.prank(IXERC20(blastXERC20).owner()); |
||||||
|
IXERC20(blastXERC20).setLimits(address(hypXERC20), amount, amount); |
||||||
|
|
||||||
|
// test sending `amount` on warp route |
||||||
|
vm.prank(0x7BE481D464CAD7ad99500CE8A637599eB8d0FCDB); // ezETH whale |
||||||
|
IXERC20(blastXERC20).transfer(address(this), amount); |
||||||
|
IXERC20(blastXERC20).approve(address(hypXERC20), amount); |
||||||
|
uint256 value = hypXERC20.quoteGasPayment(ethereumDomainId); |
||||||
|
hypXERC20.transferRemote{value: value}( |
||||||
|
ethereumDomainId, |
||||||
|
recipient, |
||||||
|
amount |
||||||
|
); |
||||||
|
|
||||||
|
// test receiving `amount` on warp route |
||||||
|
vm.prank(blastMailbox); |
||||||
|
hypXERC20.handle( |
||||||
|
ethereumDomainId, |
||||||
|
address(hypXERC20Lockbox).addressToBytes32(), |
||||||
|
tokenMessage |
||||||
|
); |
||||||
|
|
||||||
|
vm.selectFork(ethereumFork); |
||||||
|
hypXERC20Lockbox.enrollRemoteRouter( |
||||||
|
blastDomainId, |
||||||
|
address(hypXERC20).addressToBytes32() |
||||||
|
); |
||||||
|
|
||||||
|
// grant `amount` mint and burn limit to warp route |
||||||
|
IXERC20 ethereumXERC20 = hypXERC20Lockbox.xERC20(); |
||||||
|
vm.prank(ethereumXERC20.owner()); |
||||||
|
ethereumXERC20.setLimits(address(hypXERC20Lockbox), amount, amount); |
||||||
|
|
||||||
|
// test sending `amount` on warp route |
||||||
|
IERC20 erc20 = IXERC20Lockbox(ethereumLockbox).ERC20(); |
||||||
|
vm.prank(ethereumLockbox); |
||||||
|
erc20.transfer(address(this), amount); |
||||||
|
erc20.approve(address(hypXERC20Lockbox), amount); |
||||||
|
hypXERC20Lockbox.transferRemote(blastDomainId, recipient, amount); |
||||||
|
|
||||||
|
// test receiving `amount` on warp route |
||||||
|
vm.prank(ethereumMailbox); |
||||||
|
hypXERC20Lockbox.handle( |
||||||
|
blastDomainId, |
||||||
|
address(hypXERC20).addressToBytes32(), |
||||||
|
tokenMessage |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||||
|
pragma solidity >=0.8.0; |
||||||
|
|
||||||
|
import "forge-std/Vm.sol"; |
||||||
|
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; |
||||||
|
|
||||||
|
// see https://book.getfoundry.sh/reference/anvil/#supported-rpc-methods |
||||||
|
library AnvilRPC { |
||||||
|
using Strings for address; |
||||||
|
using Strings for uint256; |
||||||
|
|
||||||
|
using AnvilRPC for string; |
||||||
|
using AnvilRPC for string[1]; |
||||||
|
using AnvilRPC for string[2]; |
||||||
|
using AnvilRPC for string[3]; |
||||||
|
|
||||||
|
Vm private constant vm = |
||||||
|
Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); |
||||||
|
|
||||||
|
string private constant OPEN_ARRAY = "["; |
||||||
|
string private constant CLOSE_ARRAY = "]"; |
||||||
|
string private constant COMMA = ","; |
||||||
|
string private constant EMPTY_ARRAY = "[]"; |
||||||
|
|
||||||
|
function escaped( |
||||||
|
string memory value |
||||||
|
) internal pure returns (string memory) { |
||||||
|
return string.concat(ESCAPED_QUOTE, value, ESCAPED_QUOTE); |
||||||
|
} |
||||||
|
|
||||||
|
function toString( |
||||||
|
string[1] memory values |
||||||
|
) internal pure returns (string memory) { |
||||||
|
return string.concat(OPEN_ARRAY, values[0], CLOSE_ARRAY); |
||||||
|
} |
||||||
|
|
||||||
|
function toString( |
||||||
|
string[2] memory values |
||||||
|
) internal pure returns (string memory) { |
||||||
|
return |
||||||
|
string.concat(OPEN_ARRAY, values[0], COMMA, values[1], CLOSE_ARRAY); |
||||||
|
} |
||||||
|
|
||||||
|
function toString( |
||||||
|
string[3] memory values |
||||||
|
) internal pure returns (string memory) { |
||||||
|
return |
||||||
|
string.concat( |
||||||
|
OPEN_ARRAY, |
||||||
|
values[0], |
||||||
|
COMMA, |
||||||
|
values[1], |
||||||
|
COMMA, |
||||||
|
values[2], |
||||||
|
CLOSE_ARRAY |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function impersonateAccount(address account) internal { |
||||||
|
vm.rpc( |
||||||
|
"anvil_impersonateAccount", |
||||||
|
[account.toHexString().escaped()].toString() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function setBalance(address account, uint256 balance) internal { |
||||||
|
vm.rpc( |
||||||
|
"anvil_setBalance", |
||||||
|
[account.toHexString().escaped(), balance.toString()].toString() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function setCode(address account, bytes memory code) internal { |
||||||
|
vm.rpc( |
||||||
|
"anvil_setCode", |
||||||
|
[account.toHexString().escaped(), string(code).escaped()].toString() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function setStorageAt( |
||||||
|
address account, |
||||||
|
uint256 slot, |
||||||
|
uint256 value |
||||||
|
) internal { |
||||||
|
vm.rpc( |
||||||
|
"anvil_setStorageAt", |
||||||
|
[ |
||||||
|
account.toHexString().escaped(), |
||||||
|
slot.toHexString(), |
||||||
|
value.toHexString() |
||||||
|
].toString() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function resetFork(string memory rpcUrl) internal { |
||||||
|
string memory obj = string.concat( |
||||||
|
// solhint-disable-next-line quotes |
||||||
|
'{"forking":{"jsonRpcUrl":', |
||||||
|
string(rpcUrl).escaped(), |
||||||
|
"}}" |
||||||
|
); |
||||||
|
vm.rpc("anvil_reset", [obj].toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// here to prevent syntax highlighting from breaking |
||||||
|
string constant ESCAPED_QUOTE = '"'; |
@ -0,0 +1,436 @@ |
|||||||
|
{ |
||||||
|
"annotations": { |
||||||
|
"list": [ |
||||||
|
{ |
||||||
|
"builtIn": 1, |
||||||
|
"datasource": { |
||||||
|
"type": "grafana", |
||||||
|
"uid": "-- Grafana --" |
||||||
|
}, |
||||||
|
"enable": true, |
||||||
|
"hide": true, |
||||||
|
"iconColor": "rgba(0, 211, 255, 1)", |
||||||
|
"name": "Annotations & Alerts", |
||||||
|
"type": "dashboard" |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
"editable": true, |
||||||
|
"fiscalYearStartMonth": 0, |
||||||
|
"graphTooltip": 0, |
||||||
|
"id": 66, |
||||||
|
"links": [], |
||||||
|
"panels": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"description": "There shouldn't be abrupt changes, especially for a specific pair", |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"color": { |
||||||
|
"mode": "palette-classic" |
||||||
|
}, |
||||||
|
"custom": { |
||||||
|
"axisBorderShow": false, |
||||||
|
"axisCenteredZero": false, |
||||||
|
"axisColorMode": "text", |
||||||
|
"axisLabel": "", |
||||||
|
"axisPlacement": "auto", |
||||||
|
"barAlignment": 0, |
||||||
|
"drawStyle": "bars", |
||||||
|
"fillOpacity": 78, |
||||||
|
"gradientMode": "none", |
||||||
|
"hideFrom": { |
||||||
|
"legend": false, |
||||||
|
"tooltip": false, |
||||||
|
"viz": false |
||||||
|
}, |
||||||
|
"insertNulls": false, |
||||||
|
"lineInterpolation": "linear", |
||||||
|
"lineWidth": 1, |
||||||
|
"pointSize": 5, |
||||||
|
"scaleDistribution": { |
||||||
|
"type": "linear" |
||||||
|
}, |
||||||
|
"showPoints": "auto", |
||||||
|
"spanNulls": false, |
||||||
|
"stacking": { |
||||||
|
"group": "A", |
||||||
|
"mode": "normal" |
||||||
|
}, |
||||||
|
"thresholdsStyle": { |
||||||
|
"mode": "off" |
||||||
|
} |
||||||
|
}, |
||||||
|
"mappings": [], |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"overrides": [] |
||||||
|
}, |
||||||
|
"gridPos": { |
||||||
|
"h": 9, |
||||||
|
"w": 12, |
||||||
|
"x": 0, |
||||||
|
"y": 0 |
||||||
|
}, |
||||||
|
"id": 2, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"calcs": [], |
||||||
|
"displayMode": "list", |
||||||
|
"placement": "bottom", |
||||||
|
"showLegend": true |
||||||
|
}, |
||||||
|
"tooltip": { |
||||||
|
"maxHeight": 600, |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"editorMode": "code", |
||||||
|
"expr": "sum by (origin,remote)(round(increase(hyperlane_messages_processed_count[5m])))", |
||||||
|
"hide": false, |
||||||
|
"interval": "", |
||||||
|
"legendFormat": "{{hyperlane_deployment}}: {{origin}}->{{remote}}", |
||||||
|
"range": true, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Messages Processed", |
||||||
|
"type": "timeseries" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"color": { |
||||||
|
"mode": "palette-classic" |
||||||
|
}, |
||||||
|
"custom": { |
||||||
|
"axisBorderShow": false, |
||||||
|
"axisCenteredZero": false, |
||||||
|
"axisColorMode": "text", |
||||||
|
"axisLabel": "", |
||||||
|
"axisPlacement": "auto", |
||||||
|
"barAlignment": 0, |
||||||
|
"drawStyle": "line", |
||||||
|
"fillOpacity": 0, |
||||||
|
"gradientMode": "none", |
||||||
|
"hideFrom": { |
||||||
|
"legend": false, |
||||||
|
"tooltip": false, |
||||||
|
"viz": false |
||||||
|
}, |
||||||
|
"insertNulls": false, |
||||||
|
"lineInterpolation": "linear", |
||||||
|
"lineWidth": 1, |
||||||
|
"pointSize": 5, |
||||||
|
"scaleDistribution": { |
||||||
|
"type": "linear" |
||||||
|
}, |
||||||
|
"showPoints": "auto", |
||||||
|
"spanNulls": false, |
||||||
|
"stacking": { |
||||||
|
"group": "A", |
||||||
|
"mode": "none" |
||||||
|
}, |
||||||
|
"thresholdsStyle": { |
||||||
|
"mode": "off" |
||||||
|
} |
||||||
|
}, |
||||||
|
"mappings": [], |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"overrides": [] |
||||||
|
}, |
||||||
|
"gridPos": { |
||||||
|
"h": 9, |
||||||
|
"w": 12, |
||||||
|
"x": 0, |
||||||
|
"y": 9 |
||||||
|
}, |
||||||
|
"id": 1, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"calcs": [], |
||||||
|
"displayMode": "list", |
||||||
|
"placement": "bottom", |
||||||
|
"showLegend": true |
||||||
|
}, |
||||||
|
"tooltip": { |
||||||
|
"maxHeight": 600, |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"editorMode": "code", |
||||||
|
"expr": "sum by (remote, queue_name)(\n hyperlane_submitter_queue_length{queue_name=\"prepare_queue\"}\n)", |
||||||
|
"interval": "", |
||||||
|
"legendFormat": "{{hyperlane_deployment }} - {{remote}}", |
||||||
|
"range": true, |
||||||
|
"refId": "A" |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Prepare queues (all)", |
||||||
|
"type": "timeseries" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"color": { |
||||||
|
"mode": "palette-classic" |
||||||
|
}, |
||||||
|
"custom": { |
||||||
|
"axisBorderShow": false, |
||||||
|
"axisCenteredZero": false, |
||||||
|
"axisColorMode": "text", |
||||||
|
"axisLabel": "", |
||||||
|
"axisPlacement": "auto", |
||||||
|
"barAlignment": 0, |
||||||
|
"drawStyle": "line", |
||||||
|
"fillOpacity": 0, |
||||||
|
"gradientMode": "none", |
||||||
|
"hideFrom": { |
||||||
|
"legend": false, |
||||||
|
"tooltip": false, |
||||||
|
"viz": false |
||||||
|
}, |
||||||
|
"insertNulls": false, |
||||||
|
"lineInterpolation": "linear", |
||||||
|
"lineWidth": 1, |
||||||
|
"pointSize": 5, |
||||||
|
"scaleDistribution": { |
||||||
|
"type": "linear" |
||||||
|
}, |
||||||
|
"showPoints": "auto", |
||||||
|
"spanNulls": false, |
||||||
|
"stacking": { |
||||||
|
"group": "A", |
||||||
|
"mode": "none" |
||||||
|
}, |
||||||
|
"thresholdsStyle": { |
||||||
|
"mode": "off" |
||||||
|
} |
||||||
|
}, |
||||||
|
"mappings": [], |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"overrides": [] |
||||||
|
}, |
||||||
|
"gridPos": { |
||||||
|
"h": 8, |
||||||
|
"w": 12, |
||||||
|
"x": 0, |
||||||
|
"y": 18 |
||||||
|
}, |
||||||
|
"id": 10, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"calcs": [], |
||||||
|
"displayMode": "list", |
||||||
|
"placement": "bottom", |
||||||
|
"showLegend": true |
||||||
|
}, |
||||||
|
"tooltip": { |
||||||
|
"maxHeight": 600, |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"disableTextWrap": false, |
||||||
|
"editorMode": "code", |
||||||
|
"expr": "sum by(remote, queue_name) (hyperlane_submitter_queue_length{queue_name=\"submit_queue\"})", |
||||||
|
"fullMetaSearch": false, |
||||||
|
"includeNullMetadata": true, |
||||||
|
"interval": "", |
||||||
|
"legendFormat": "{{remote}}", |
||||||
|
"range": true, |
||||||
|
"refId": "A", |
||||||
|
"useBackend": false |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Submit Queues", |
||||||
|
"type": "timeseries" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"fieldConfig": { |
||||||
|
"defaults": { |
||||||
|
"color": { |
||||||
|
"mode": "palette-classic" |
||||||
|
}, |
||||||
|
"custom": { |
||||||
|
"axisBorderShow": false, |
||||||
|
"axisCenteredZero": false, |
||||||
|
"axisColorMode": "text", |
||||||
|
"axisLabel": "", |
||||||
|
"axisPlacement": "auto", |
||||||
|
"barAlignment": 0, |
||||||
|
"drawStyle": "line", |
||||||
|
"fillOpacity": 0, |
||||||
|
"gradientMode": "none", |
||||||
|
"hideFrom": { |
||||||
|
"legend": false, |
||||||
|
"tooltip": false, |
||||||
|
"viz": false |
||||||
|
}, |
||||||
|
"insertNulls": false, |
||||||
|
"lineInterpolation": "linear", |
||||||
|
"lineWidth": 1, |
||||||
|
"pointSize": 5, |
||||||
|
"scaleDistribution": { |
||||||
|
"type": "linear" |
||||||
|
}, |
||||||
|
"showPoints": "auto", |
||||||
|
"spanNulls": false, |
||||||
|
"stacking": { |
||||||
|
"group": "A", |
||||||
|
"mode": "none" |
||||||
|
}, |
||||||
|
"thresholdsStyle": { |
||||||
|
"mode": "off" |
||||||
|
} |
||||||
|
}, |
||||||
|
"mappings": [], |
||||||
|
"thresholds": { |
||||||
|
"mode": "absolute", |
||||||
|
"steps": [ |
||||||
|
{ |
||||||
|
"color": "green", |
||||||
|
"value": null |
||||||
|
}, |
||||||
|
{ |
||||||
|
"color": "red", |
||||||
|
"value": 80 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"overrides": [] |
||||||
|
}, |
||||||
|
"gridPos": { |
||||||
|
"h": 8, |
||||||
|
"w": 12, |
||||||
|
"x": 0, |
||||||
|
"y": 26 |
||||||
|
}, |
||||||
|
"id": 8, |
||||||
|
"options": { |
||||||
|
"legend": { |
||||||
|
"calcs": [], |
||||||
|
"displayMode": "list", |
||||||
|
"placement": "bottom", |
||||||
|
"showLegend": true |
||||||
|
}, |
||||||
|
"tooltip": { |
||||||
|
"maxHeight": 600, |
||||||
|
"mode": "single", |
||||||
|
"sort": "none" |
||||||
|
} |
||||||
|
}, |
||||||
|
"targets": [ |
||||||
|
{ |
||||||
|
"datasource": { |
||||||
|
"type": "prometheus", |
||||||
|
"uid": "grafanacloud-prom" |
||||||
|
}, |
||||||
|
"disableTextWrap": false, |
||||||
|
"editorMode": "code", |
||||||
|
"expr": "sum by(remote, queue_name) (avg_over_time(hyperlane_submitter_queue_length{queue_name=\"confirm_queue\"}[20m]))", |
||||||
|
"fullMetaSearch": false, |
||||||
|
"includeNullMetadata": true, |
||||||
|
"interval": "", |
||||||
|
"legendFormat": "{{remote}}", |
||||||
|
"range": true, |
||||||
|
"refId": "A", |
||||||
|
"useBackend": false |
||||||
|
} |
||||||
|
], |
||||||
|
"title": "Confirm Queues", |
||||||
|
"type": "timeseries" |
||||||
|
} |
||||||
|
], |
||||||
|
"refresh": "1m", |
||||||
|
"schemaVersion": 39, |
||||||
|
"tags": [], |
||||||
|
"templating": { |
||||||
|
"list": [] |
||||||
|
}, |
||||||
|
"time": { |
||||||
|
"from": "now-7d", |
||||||
|
"to": "now" |
||||||
|
}, |
||||||
|
"timeRangeUpdatedDuringEditOrView": false, |
||||||
|
"timepicker": {}, |
||||||
|
"timezone": "browser", |
||||||
|
"title": "Easy Dashboard (External Sharing Template)", |
||||||
|
"uid": "afdf6ada6uzvgga", |
||||||
|
"version": 5, |
||||||
|
"weekStart": "" |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue