Skip to content

Commit

Permalink
added solhint and updated readme
Browse files Browse the repository at this point in the history
  • Loading branch information
dan13ram committed Sep 8, 2024
1 parent d64144b commit 88fc62b
Show file tree
Hide file tree
Showing 22 changed files with 1,189 additions and 189 deletions.
3 changes: 3 additions & 0 deletions .solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "solhint:default"
}
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This repository includes:
- **Smart Contracts**: Contracts for Yieldnest's cross-chain tokens.
- **Deployment Scripts**: Scripts for deploying and configuring the contracts across multiple chains.
- **Testing Framework**: Tests using Foundry's Forge tool.

### Key Contracts and Scripts

- **Main Contracts**:
Expand Down Expand Up @@ -70,22 +70,30 @@ forge compile
Run the tests with the following command:

```bash
forge test -vvv
yarn test
```

### Lint

To lint Solidity files using `solhint`, run:

```bash
yarn lint
```

The `-vvv` flag provides verbose output for more detailed test results.
This will check all Solidity files in the `src/`, `test/`, and `scripts/` directories for issues, adhering to the project's `solhint` configuration.

### Format

You can format your Solidity code using:

```bash
forge fmt
yarn format
```

### Deploy
### Scripts

To deploy one of the main scripts (e.g., `DeployMultiChainDeployer`), use the following pattern:
To run one of the scripts (e.g., `DeployMultiChainDeployer`), use the following pattern:

```bash
forge script script/DeployMultiChainDeployer.s.sol:DeployMultiChainDeployer \
Expand All @@ -104,14 +112,6 @@ To generate gas usage reports for the contracts, run:
forge snapshot
```

### Anvil

You can use Anvil, the local Ethereum testnet, with:

```bash
anvil
```

## Project Structure

- `src/`: Contains the core smart contracts for the project.
Expand All @@ -126,6 +126,8 @@ anvil

This project uses `husky` for Git hooks and `forge fmt` for Solidity file formatting. Pre-commit hooks are set up using `lint-staged` to automatically format `.sol` files on commit.

In addition, `solhint` is used to lint Solidity files. You can run `yarn lint` to manually check the code for common issues and enforce style guidelines.

## Documentation

For more information on Foundry and how to use it, please refer to the [Foundry Book](https://book.getfoundry.sh/).
Expand Down
6 changes: 6 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ evm_version = "cancun"
solc_version = "0.8.24"
prompt_timeout = 120

[fmt]
single_line_statement_blocks = "multi"
multiline_func_header = "all"
sort_imports = true
line_length = 100

[rpc_endpoints]
mainnet = "${MAINNET_RPC_URL}"
arbitrum = "${ARBITRUM_RPC_URL}"
Expand Down
29 changes: 16 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
"name": "yieldnest-cross-chain",
"description": "Contracts and scripts for deploying cross chain yieldnest tokens using LayerZero.",
"version": "0.1.0",
"dependencies": {
"@layerzerolabs/lz-evm-v1-0.7": "^2.3.40",
"hardhat-deploy": "^0.12.4",
"lint-staged": "^15.2.10",
"solmate": "^6.2.0"
},
"devDependencies": {
"@layerzerolabs/lz-evm-messagelib-v2": "^2.1.27",
"@layerzerolabs/lz-evm-oapp-v2": "^2.1.18",
Expand All @@ -11,27 +17,24 @@
"forge-std": "github:foundry-rs/forge-std#v1.8.1",
"husky": "^9.1.5",
"layerzero-v2": "github:JorgeAtPaladin/LayerZero-v2#lz-upgrade",
"solhint": "^5.0.3",
"solidity-bytes-utils": "^0.8.2"
},
"license": "MIT",
"lint-staged": {
"*.sol": [
"solhint --fix --noPrompt",
"forge fmt"
]
},
"main": "index.js",
"repository": "https://github.com/yieldnest/yieldnest-cross-chain",
"scripts": {
"build": "yarn install && forge build",
"compile": "forge compile",
"format": "forge fmt --root .",
"test": "forge test -vvv",
"prepare": "husky"
},
"lint-staged": {
"*.sol": [
"forge fmt"
]
},
"dependencies": {
"@layerzerolabs/lz-evm-v1-0.7": "^2.3.40",
"hardhat-deploy": "^0.12.4",
"lint-staged": "^15.2.10",
"solmate": "^6.2.0"
"lint": "solhint \"src/**/*.sol\" && solhint \"test/**/*.sol\" && solhint \"script/**/*.sol\"",
"prepare": "husky",
"test": "forge test -vvv"
}
}
6 changes: 4 additions & 2 deletions script/BaseData.s.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* solhint-disable no-console */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

Expand Down Expand Up @@ -75,8 +76,9 @@ contract BaseData is Script {
}

function isSupportedChainId(uint256 chainId) internal view returns (bool) {
bool isSupported = chainId == __chainIds.mainnet || chainId == __chainIds.base || chainId == __chainIds.fraxtal
|| chainId == __chainIds.optimism || chainId == __chainIds.arbitrum || chainId == __chainIds.holesky
bool isSupported = chainId == __chainIds.mainnet || chainId == __chainIds.base
|| chainId == __chainIds.fraxtal || chainId == __chainIds.optimism
|| chainId == __chainIds.arbitrum || chainId == __chainIds.holesky
|| chainId == __chainIds.fraxtalTestnet;
bool isEID = __chainIdToLzEID[chainId] != 0;
return isSupported && isEID;
Expand Down
57 changes: 43 additions & 14 deletions script/BaseScript.s.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* solhint-disable no-console */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

Expand Down Expand Up @@ -48,11 +49,15 @@ contract BaseScript is BaseData {
RateLimiter.RateLimitConfig[] memory rateLimitConfigs =
new RateLimiter.RateLimitConfig[](baseInput.l2ChainIds.length + 1);
rateLimitConfigs[0] = RateLimiter.RateLimitConfig(
getEID(baseInput.l1ChainId), baseInput.rateLimitConfig.limit, baseInput.rateLimitConfig.window
getEID(baseInput.l1ChainId),
baseInput.rateLimitConfig.limit,
baseInput.rateLimitConfig.window
);
for (uint256 i; i < baseInput.l2ChainIds.length; i++) {
rateLimitConfigs[i + 1] = RateLimiter.RateLimitConfig(
getEID(baseInput.l2ChainIds[i]), baseInput.rateLimitConfig.limit, baseInput.rateLimitConfig.window
getEID(baseInput.l2ChainIds[i]),
baseInput.rateLimitConfig.limit,
baseInput.rateLimitConfig.window
);
}
return rateLimitConfigs;
Expand Down Expand Up @@ -113,7 +118,12 @@ contract BaseScript is BaseData {
function _getDeploymentFilePath() internal view returns (string memory) {
return string(
abi.encodePacked(
vm.projectRoot(), "/deployments/", baseInput.erc20Symbol, "-", vm.toString(baseInput.l1ChainId), ".json"
vm.projectRoot(),
"/deployments/",
baseInput.erc20Symbol,
"-",
vm.toString(baseInput.l1ChainId),
".json"
)
);
}
Expand All @@ -131,7 +141,8 @@ contract BaseScript is BaseData {
if (!found) {
deployment.chains.push(currentDeployment);
}
string memory json = vm.serializeAddress("deployment", "deployerAddress", deployment.deployerAddress);
string memory json =
vm.serializeAddress("deployment", "deployerAddress", deployment.deployerAddress);

string memory chainsJson = "";

Expand All @@ -142,11 +153,15 @@ contract BaseScript is BaseData {
chainJson = vm.serializeUint(chainKey, "chainId", deployment.chains[i].chainId);
chainJson = vm.serializeAddress(chainKey, "lzEndpoint", deployment.chains[i].lzEndpoint);
chainJson = vm.serializeUint(chainKey, "lzEID", deployment.chains[i].lzEID);
chainJson = vm.serializeAddress(chainKey, "multiChainDeployer", deployment.chains[i].multiChainDeployer);
chainJson = vm.serializeAddress(chainKey, "erc20Address", deployment.chains[i].erc20Address);
chainJson = vm.serializeAddress(
chainKey, "multiChainDeployer", deployment.chains[i].multiChainDeployer
);
chainJson =
vm.serializeAddress(chainKey, "erc20Address", deployment.chains[i].erc20Address);
chainJson = vm.serializeAddress(chainKey, "oftAdapter", deployment.chains[i].oftAdapter);

chainsJson = vm.serializeString("chains", vm.toString(deployment.chains[i].chainId), chainJson);
chainsJson =
vm.serializeString("chains", vm.toString(deployment.chains[i].chainId), chainJson);
}

json = vm.serializeString("deployment", "chains", chainsJson);
Expand Down Expand Up @@ -179,13 +194,18 @@ contract BaseScript is BaseData {
string memory chainKey = string(abi.encodePacked(".chains.", chainKeys[i]));

chains[i].isL1 = vm.parseJsonBool(json, string(abi.encodePacked(chainKey, ".isL1")));
chains[i].chainId = vm.parseJsonUint(json, string(abi.encodePacked(chainKey, ".chainId")));
chains[i].lzEndpoint = vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".lzEndpoint")));
chains[i].lzEID = uint32(vm.parseJsonUint(json, string(abi.encodePacked(chainKey, ".lzEID"))));
chains[i].chainId =
vm.parseJsonUint(json, string(abi.encodePacked(chainKey, ".chainId")));
chains[i].lzEndpoint =
vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".lzEndpoint")));
chains[i].lzEID =
uint32(vm.parseJsonUint(json, string(abi.encodePacked(chainKey, ".lzEID"))));
chains[i].multiChainDeployer =
vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".multiChainDeployer")));
chains[i].erc20Address = vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".erc20Address")));
chains[i].oftAdapter = vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".oftAdapter")));
chains[i].erc20Address =
vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".erc20Address")));
chains[i].oftAdapter =
vm.parseJsonAddress(json, string(abi.encodePacked(chainKey, ".oftAdapter")));

// Add the chain to the deployment
deployment.chains.push(chains[i]);
Expand Down Expand Up @@ -215,9 +235,18 @@ contract BaseScript is BaseData {
baseInput.rateLimitConfig.window = vm.parseJsonUint(json, ".rateLimitConfig.window");
}

function createSalt(address _deployerAddress, string memory _label) internal pure returns (bytes32 _salt) {
function createSalt(
address _deployerAddress,
string memory _label
)
internal
pure
returns (bytes32 _salt)
{
_salt = bytes32(
abi.encodePacked(bytes20(_deployerAddress), bytes12(bytes32(keccak256(abi.encode(_label, _version)))))
abi.encodePacked(
bytes20(_deployerAddress), bytes12(bytes32(keccak256(abi.encode(_label, _version))))
)
);
}

Expand Down
19 changes: 14 additions & 5 deletions script/DeployL1OFTAdapter.s.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/* solhint-disable no-console */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {BaseScript} from "./BaseScript.s.sol";
import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol";

import {L1YnOFTAdapterUpgradeable} from "@/L1YnOFTAdapterUpgradeable.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol";
import {TransparentUpgradeableProxy} from
"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {console} from "forge-std/console.sol";

// forge script script/DeployL1OFTAdapter.s.sol:DeployL1OFTAdapter --rpc-url ${rpc} --sig "run(string calldata)" ${path} --account ${deployerAccountName} --sender ${deployer} --broadcast --etherscan-api-key ${api} --verify
// forge script script/DeployL1OFTAdapter.s.sol:DeployL1OFTAdapter \
// --rpc-url ${rpc} --sig "run(string calldata)" ${path} \
// --account ${deployerAccountName} --sender ${deployer} \
// --broadcast --etherscan-api-key ${api} --verify

contract DeployL1OFTAdapter is BaseScript {
L1YnOFTAdapterUpgradeable public l1OFTAdapter;
Expand All @@ -25,7 +31,8 @@ contract DeployL1OFTAdapter is BaseScript {
bool needsChange = false;

for (uint256 i = 0; i < rateLimitConfigs.length; i++) {
(,, uint256 limit, uint256 window) = l1OFTAdapter.rateLimits(rateLimitConfigs[i].dstEid);
(,, uint256 limit, uint256 window) =
l1OFTAdapter.rateLimits(rateLimitConfigs[i].dstEid);
RateLimiter.RateLimitConfig memory config = rateLimitConfigs[i];
if (config.limit != limit || config.window != window) {
needsChange = true;
Expand Down Expand Up @@ -56,7 +63,9 @@ contract DeployL1OFTAdapter is BaseScript {
);

bytes memory initializeData = abi.encodeWithSelector(
L1YnOFTAdapterUpgradeable.initialize.selector, getAddresses().OFT_DELEGATE, rateLimitConfigs
L1YnOFTAdapterUpgradeable.initialize.selector,
getAddresses().OFT_DELEGATE,
rateLimitConfigs
);

l1OFTAdapter = L1YnOFTAdapterUpgradeable(
Expand Down
22 changes: 16 additions & 6 deletions script/DeployL2OFTAdapter.s.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
/* solhint-disable no-console */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {BaseScript} from "./BaseScript.s.sol";

import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol";
import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol";
import {IImmutableMultiChainDeployer} from "@interfaces/IImmutableMultiChainDeployer.sol";
import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol";
import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol";
import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import {TransparentUpgradeableProxy} from
"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {console} from "forge-std/console.sol";

// forge script script/DeployL2OFTAdapter.s.sol:DeployL2Adapter --rpc-url ${rpc} --sig "run(string memory, string memory)" ${path2ERC20Input} ${path2OFTAdapterInput} --account ${deployerAccountName} --sender ${deployer} --broadcast --etherscan-api-key ${api} --verify
// forge script script/DeployL2OFTAdapter.s.sol:DeployL2Adapter \
// --rpc-url ${rpc} --sig "run(string calldata)" ${path} \
// --account ${deployerAccountName} --sender ${deployer} \
// --broadcast --etherscan-api-key ${api} --verify

contract DeployL2OFTAdapter is BaseScript {
L2YnOFTAdapterUpgradeable l2OFTAdapter;
Expand All @@ -20,7 +27,9 @@ contract DeployL2OFTAdapter is BaseScript {

require(currentDeployment.isL1 != true, "Must be L2 deployment");

require(currentDeployment.multiChainDeployer != address(0), "MultiChainDeployer not deployed");
require(
currentDeployment.multiChainDeployer != address(0), "MultiChainDeployer not deployed"
);

IImmutableMultiChainDeployer currentDeployer =
IImmutableMultiChainDeployer(currentDeployment.multiChainDeployer);
Expand All @@ -33,7 +42,8 @@ contract DeployL2OFTAdapter is BaseScript {
bool needsChange = false;

for (uint256 i = 0; i < rateLimitConfigs.length; i++) {
(,, uint256 limit, uint256 window) = l2OFTAdapter.rateLimits(rateLimitConfigs[i].dstEid);
(,, uint256 limit, uint256 window) =
l2OFTAdapter.rateLimits(rateLimitConfigs[i].dstEid);
RateLimiter.RateLimitConfig memory config = rateLimitConfigs[i];
if (config.limit != limit || config.window != window) {
needsChange = true;
Expand Down
16 changes: 12 additions & 4 deletions script/DeployMultiChainDeployer.s.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/* solhint-disable no-console */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {BaseScript} from "./BaseScript.s.sol";
import {ImmutableMultiChainDeployer} from "@factory/ImmutableMultiChainDeployer.sol";
import {console} from "forge-std/console.sol";

//forge script script/DeployMultiChainDeployer.s.sol:DeployMultiChainDeployer --rpc-url ${rpc} --sig "run(string calldata)" ${path} --account ${deployerAccountName} --sender ${deployer} --broadcast --etherscan-api-key ${api} --verify
// forge script script/DeployMultiChainDeployer.s.sol:DeployMultiChainDeployer \
// --rpc-url ${rpc} --sig "run(string calldata)" ${path} \
// --account ${deployerAccountName} --sender ${deployer} \
// --broadcast --etherscan-api-key ${api} --verify

contract DeployMultiChainDeployer is BaseScript {
address public multiChainDeployerAddress;
Expand All @@ -17,13 +21,17 @@ contract DeployMultiChainDeployer is BaseScript {

bytes32 salt = createSalt(msg.sender, "ImmutableMultiChainDeployer");

address predictedAddress =
vm.computeCreate2Address(salt, keccak256(type(ImmutableMultiChainDeployer).creationCode));
address predictedAddress = vm.computeCreate2Address(
salt, keccak256(type(ImmutableMultiChainDeployer).creationCode)
);
console.log("Predicted ImmutableMultiChainDeployer address: ", predictedAddress);

if (currentDeployment.multiChainDeployer != address(0)) {
require(currentDeployment.multiChainDeployer == predictedAddress, "Already deployed");
console.log("ImmutableMultiChainDeployer already deployed at: ", currentDeployment.multiChainDeployer);
console.log(
"ImmutableMultiChainDeployer already deployed at: ",
currentDeployment.multiChainDeployer
);
return;
}

Expand Down
Loading

0 comments on commit 88fc62b

Please sign in to comment.