commit
70c4c28c2f
@ -0,0 +1,6 @@ |
||||
--- |
||||
'@hyperlane-xyz/core': patch |
||||
'@hyperlane-xyz/helloworld': patch |
||||
--- |
||||
|
||||
fix: `TokenRouter.transferRemote` with hook overrides |
@ -0,0 +1,5 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': patch |
||||
--- |
||||
|
||||
Do not consider xERC20 a collateral standard to fix fungibility checking logic while maintaining mint limit checking |
@ -1,20 +0,0 @@ |
||||
{ |
||||
"mode": "pre", |
||||
"tag": "alpha", |
||||
"initialVersions": { |
||||
"@hyperlane-xyz/core": "4.0.0-alpha.0", |
||||
"@hyperlane-xyz/ccip-server": "4.0.0-alpha.0", |
||||
"@hyperlane-xyz/cli": "4.0.0-alpha.0", |
||||
"@hyperlane-xyz/helloworld": "4.0.0-alpha.0", |
||||
"@hyperlane-xyz/infra": "4.0.0-alpha.0", |
||||
"@hyperlane-xyz/sdk": "4.0.0-alpha.0", |
||||
"@hyperlane-xyz/utils": "4.0.0-alpha.0" |
||||
}, |
||||
"changesets": [ |
||||
"bright-emus-double", |
||||
"five-baboons-smoke", |
||||
"late-rings-attack", |
||||
"sharp-geckos-wash", |
||||
"slimy-toys-argue" |
||||
] |
||||
} |
@ -0,0 +1,6 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': patch |
||||
'@hyperlane-xyz/sdk': patch |
||||
--- |
||||
|
||||
Support priorityFee fetching from RPC and some better logging |
@ -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::*}; |
||||
|
||||
mod interchain_gas; |
||||
|
||||
mod mailbox; |
||||
|
||||
mod merkle_tree_hook; |
||||
|
||||
mod multicall; |
||||
|
||||
mod utils; |
||||
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(), |
||||
} |
||||
} |
||||
} |
@ -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 = '"'; |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue