-
Notifications
You must be signed in to change notification settings - Fork 280
ποΈ foundry scripts for LayerZero #1334
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
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
ddeeac6
init
shankars99 fb70e9c
feat: imported simulate receive https://github.com/DanL0/integrationsβ¦
shankars99 475b700
recursively export the scripts
shankars99 0c5fb6a
export artifacts
shankars99 60db891
rename scripts -> script. foundry defaults to script and we dont overβ¦
shankars99 ee65560
make run() virtual
shankars99 3bcc85d
move gasprofiling from /examples/oft
shankars99 5c586b1
add @layerzerolabs/script-devtools-evm-foundry/ and remappings
shankars99 91de463
pnpm-lock
shankars99 1c29225
remove base foundry Script import
shankars99 c0efbc7
changelog
ravinagill15 74f136f
fixed lockfile
ravinagill15 463518d
updated forge commit
ravinagill15 cf98cb6
renamed dir to scripts
ravinagill15 404d28c
removed redundant script package
ravinagill15 3ac00e1
fixed import path
ravinagill15 9d5e2e3
changeset
ravinagill15 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| "@layerzerolabs/script-devtools-evm-foundry": patch | ||
| "@layerzerolabs/toolbox-foundry": patch | ||
| "@layerzerolabs/oft-example": patch | ||
| --- | ||
|
|
||
| Added useful forge scripts and updated forge-std to latest commit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // SPDX-License-Identifier: UNLICENSED | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import { console } from "forge-std/console.sol"; | ||
|
|
||
| import { LZScripts } from "@layerzerolabs/script-devtools-evm-foundry/scripts/LZScripts.s.sol"; | ||
|
|
||
| contract LZScript is LZScripts { | ||
| function run() public pure override { | ||
| console.log("Hello, World!"); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| .turbo | ||
| dist | ||
| node_modules | ||
| out | ||
| cache |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "extends": "../../.eslintrc.json" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| cache | ||
| # Ignore everything in the artifacts folder | ||
| artifacts/* | ||
|
|
||
| # Do not ignore the directory structure up to the specific file | ||
| !artifacts/ | ||
| !artifacts/*.s.sol/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # @layerzerolabs/script-devtools-evm-foundry | ||
|
|
||
| ## 0.0.1 | ||
|
|
||
| ### Minor Changes | ||
|
|
||
| - Initial release with foundry scripts for LayerZero EVM development | ||
| - Add SimulateReceive script for simulating message reception on EVM chains | ||
| - Add GasProfiler script for profiling gas usage of OFT transfers on mainnet networks | ||
| - Add LZScripts.s.sol bundle for easy importing in custom foundry scripts | ||
| - Include foundry configuration and build artifacts for immediate use | ||
|
|
||
| ### Patch Changes | ||
|
|
||
| - @layerzerolabs/lz-evm-messagelib-v2@3.0.12 | ||
| - @layerzerolabs/lz-evm-protocol-v2@3.0.12 | ||
| - @layerzerolabs/lz-evm-v1-0.7@3.0.12 | ||
| - @layerzerolabs/toolbox-foundry@0.1.12 | ||
| - @layerzerolabs/oapp-evm@0.3.1 | ||
| - @layerzerolabs/oft-evm@3.1.2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| <p align="center"> | ||
| <a href="https://layerzero.network"> | ||
| <img alt="LayerZero" style="max-width: 500px" src="https://d3a2dpnnrypp5h.cloudfront.net/bridge-app/lz.png"/> | ||
| </a> | ||
| </p> | ||
|
|
||
| <h1 align="center">@layerzerolabs/script-devtools-evm-foundry</h1> | ||
|
|
||
| <!-- The badges section --> | ||
| <p align="center"> | ||
| <!-- Shields.io NPM published package version --> | ||
| <a href="https://www.npmjs.com/package/@layerzerolabs/script-devtools-evm-foundry"><img alt="NPM Version" src="https://img.shields.io/npm/v/@layerzerolabs/script-devtools-evm-foundry"/></a> | ||
| <!-- Shields.io NPM downloads --> | ||
| <a href="https://www.npmjs.com/package/@layerzerolabs/script-devtools-evm-foundry"><img alt="Downloads" src="https://img.shields.io/npm/dm/@layerzerolabs/script-devtools-evm-foundry"/></a> | ||
| <!-- Shields.io license badge --> | ||
| <a href="https://www.npmjs.com/package/@layerzerolabs/script-devtools-evm-foundry"><img alt="NPM License" src="https://img.shields.io/npm/l/@layerzerolabs/script-devtools-evm-foundry"/></a> | ||
| </p> | ||
|
|
||
| ## Installation | ||
|
|
||
| ```sh | ||
| $ npm install @layerzerolabs/script-devtools-evm-foundry | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| This package not only exports a bunch of scripts for you to use in your foundry projects. But since they compile into your `artifacts` folder, you can run them from your command line. | ||
|
|
||
| ```sh | ||
| forge script SimulateReceive --rpc-url YOUR_DESTINATION_CHAIN_RPC_URL --ffi | ||
| ``` | ||
|
|
||
| Since all the scripts are bundled into `LZScripts.s.sol`, you can import them in your own scripts like this: | ||
|
|
||
| ```solidity | ||
| import { LZUtils } from "@layerzerolabs/script-devtools-evm-foundry/scripts/LZScripts.s.sol"; | ||
| ``` | ||
|
|
||
| ## List of scripts | ||
|
|
||
| ### 1. SimulateReceive | ||
|
|
||
| Simulate receiving a message on an EVM chain - [Read more](./script/SimulateReceive/README.md) | ||
| Source code: [SimulateReceive.s.sol](./script/SimulateReceive/SimulateReceive.s.sol) | ||
| Shell command: | ||
|
|
||
| ```sh | ||
| forge script SimulateReceive --rpc-url $DESTINATION_CHAIN_RPC_URL --ffi | ||
| ``` | ||
|
|
||
| ### 2. GasProfiler | ||
|
|
||
| Profile the gas usage of OFT transfers on multiple mainnet networks - [Read more](./script/GasProfiling/README.md) | ||
| Source code: [OFTProfilerExample.s.sol](./script/GasProfiling/OFTProfilerExample.s.sol) | ||
| Shell command: Not available |
648 changes: 648 additions & 0 deletions
648
packages/script-devtools-evm-foundry/artifacts/GasProfiler.s.sol/GasProfilerScript.json
Large diffs are not rendered by default.
Oops, something went wrong.
843 changes: 843 additions & 0 deletions
843
packages/script-devtools-evm-foundry/artifacts/LZScripts.s.sol/LZScripts.json
Large diffs are not rendered by default.
Oops, something went wrong.
600 changes: 600 additions & 0 deletions
600
...es/script-devtools-evm-foundry/artifacts/OFTProfilerExample.s.sol/OFTProfilerExample.json
Large diffs are not rendered by default.
Oops, something went wrong.
425 changes: 425 additions & 0 deletions
425
packages/script-devtools-evm-foundry/artifacts/SimulateReceive.s.sol/SimulateReceive.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| [profile.default] | ||
| solc-version = '0.8.22' | ||
| src = 'contracts' | ||
| out = 'artifacts' | ||
| test = 'test/foundry' | ||
| cache_path = 'cache' | ||
| optimizer = true | ||
| optimizer_runs = 20_000 | ||
|
|
||
| libs = [ | ||
| # We provide a set of useful contract utilities | ||
| # in the lib directory of @layerzerolabs/toolbox-foundry: | ||
| # | ||
| # - forge-std | ||
| # - ds-test | ||
| # - solidity-bytes-utils | ||
| 'node_modules/@layerzerolabs/toolbox-foundry/lib', | ||
| 'node_modules', | ||
| ] | ||
|
|
||
| remappings = [ | ||
| # Due to a misconfiguration of solidity-bytes-utils, an outdated version | ||
| # of forge-std is being dragged in | ||
| # | ||
| # To remedy this, we'll remap the ds-test and forge-std imports to our own versions | ||
| 'ds-test/=node_modules/@layerzerolabs/toolbox-foundry/src/ds-test/src/', | ||
| 'forge-std/=node_modules/@layerzerolabs/toolbox-foundry/src/forge-std/src/', | ||
| '@layerzerolabs/=node_modules/@layerzerolabs/', | ||
| '@openzeppelin/=node_modules/@openzeppelin/', | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| { | ||
| "name": "@layerzerolabs/script-devtools-evm-foundry", | ||
| "version": "0.0.1", | ||
| "description": "Scripts to help develop LayerZero EVM contracts using foundry", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/LayerZero-Labs/devtools.git", | ||
| "directory": "packages/script-devtools-evm-foundry" | ||
| }, | ||
| "license": "MIT", | ||
| "files": [ | ||
| "contracts/", | ||
| "artifacts/", | ||
| "scripts/" | ||
| ], | ||
| "scripts": { | ||
| "build": "forge build", | ||
| "coverage": "forge coverage --ir-minimum", | ||
| "lint": "$npm_execpath eslint '**/*.{js,ts,json}'", | ||
| "lint:fix": "eslint --fix '**/*.{js,ts,json}'" | ||
| }, | ||
| "devDependencies": { | ||
| "@layerzerolabs/lz-evm-messagelib-v2": "^3.0.12", | ||
| "@layerzerolabs/lz-evm-protocol-v2": "^3.0.12", | ||
| "@layerzerolabs/lz-evm-v1-0.7": "^3.0.12", | ||
| "@layerzerolabs/toolbox-foundry": "^0.1.12", | ||
| "@openzeppelin/contracts": "^5.0.2", | ||
| "@openzeppelin/contracts-upgradeable": "^5.0.2", | ||
| "@types/node": "~18.18.14", | ||
| "solidity-bytes-utils": "^0.8.2", | ||
| "ts-node": "^10.9.2", | ||
| "typescript": "^5.4.4" | ||
| }, | ||
| "peerDependencies": { | ||
| "@layerzerolabs/lz-evm-messagelib-v2": "^3.0.12", | ||
| "@layerzerolabs/lz-evm-protocol-v2": "^3.0.12", | ||
| "@layerzerolabs/lz-evm-v1-0.7": "^3.0.12", | ||
| "@layerzerolabs/oapp-evm": "^0.3.1", | ||
| "@layerzerolabs/oft-evm": "^3.1.2", | ||
| "@openzeppelin/contracts": "^4.9.5 || ^5.0.0", | ||
| "@openzeppelin/contracts-upgradeable": "^4.9.5 || ^5.0.0" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| } | ||
| } |
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
packages/script-devtools-evm-foundry/scripts/GasProfiling/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # GasProfiling | ||
|
|
||
| Can be used to profile the gas usage of an OFT for its `lzReceive` and `lzCompose` functions. | ||
|
|
||
| Refer: [OFTProfilerExample.s.sol](./OFTProfilerExample.s.sol) |
6 changes: 6 additions & 0 deletions
6
packages/script-devtools-evm-foundry/scripts/GasProfiling/utils.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| // SPDX-License-Identifier: UNLICENSED | ||
| pragma solidity ^0.8.22; | ||
|
|
||
| import { GasProfilerScript } from "./GasProfiler.s.sol"; | ||
|
|
||
| abstract contract GasProfilingScript is GasProfilerScript {} |
11 changes: 11 additions & 0 deletions
11
packages/script-devtools-evm-foundry/scripts/LZScripts.s.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| // SPDX-License-Identifier: UNLICENSED | ||
| pragma solidity ^0.8.22; | ||
|
|
||
| import { SimulateScript } from "./SimulateReceive/utils.sol"; | ||
| import { GasProfilingScript } from "./GasProfiling/utils.sol"; | ||
|
|
||
| abstract contract LZScripts is SimulateScript, GasProfilingScript { | ||
| function IS_WORKING() public pure returns (bool) { | ||
| return true; | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
packages/script-devtools-evm-foundry/scripts/SimulateReceive/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # SimulateReceive | ||
|
|
||
| ## Usage | ||
|
|
||
| ```shell | ||
| yarn | ||
| forge build | ||
| ``` | ||
|
|
||
| 1. Find the source transaction hash of the message that has failed on [LayerZero Scan](https://layerzeroscan.com) | ||
| 2. Paste the transaction hash into `string memory txHash = "0x0c61c4db115f57b2fba78df78879f9e8230e67d75e78ac2782a3b4c929b5d12f";` in [script/SimulateReceive.s.sol](./script/SimulateReceive.s.sol) and set the mainnet boolean to `true` or `false` (for the scan API) | ||
| 4. Run: `forge script script/SimulateReceive.s.sol --rpc-url YOUR_DESTINATION_CHAIN_RPC_URL --ffi` | ||
| 5. (Optional) Add `--broadcast` and `--private-key YOUR_PRIVATE_KEY` to broadcast the transaction to the destination chain | ||
|
|
||
| If you get an error from SimulateReceive script eg. `script failed: custom error 7182306f` you can do: | ||
|
|
||
| ```shell | ||
| cast 4byte 7182306f | ||
| ``` | ||
|
|
||
| Example result: | ||
|
|
||
| ```solidity | ||
| LZ_PayloadHashNotFound(bytes32,bytes32) | ||
| ``` |
102 changes: 102 additions & 0 deletions
102
packages/script-devtools-evm-foundry/scripts/SimulateReceive/SimulateReceive.s.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| // SPDX-License-Identifier: UNLICENSED | ||
| pragma solidity ^0.8.22; | ||
|
|
||
| import { Script, console } from "forge-std/Script.sol"; | ||
| import "forge-std/StdJson.sol"; | ||
| import { Base58Decoder } from "./base58decoder.sol"; // Import the new library | ||
|
|
||
| import { IOAppCore } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol"; | ||
| import { SendParam, OFTReceipt } from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol"; | ||
| import { MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; | ||
| import { ILayerZeroEndpointV2, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; | ||
|
|
||
| // This is an exact copy of Dan Kmak's https://github.com/DanL0/integrations-foundry-tooling script that helps simulate receiving a message on an EVM chain | ||
| contract SimulateReceive is Script { | ||
| using stdJson for string; | ||
| using Base58Decoder for string; // Use the library | ||
|
|
||
| function run() public virtual { | ||
| // -- New mainnet/testnet toggle added here -- | ||
| bool mainnet = true; // Set to false for testnet | ||
| string memory txHash = "0x88a79d59222628aba22c5c616580212c80beae353aaa8ffbd3976dd5aa5d12f8"; | ||
|
|
||
| string[] memory curlCommand = new string[](5); | ||
| curlCommand[0] = "curl"; | ||
| curlCommand[1] = "-X"; | ||
| curlCommand[2] = "GET"; | ||
| curlCommand[3] = string( | ||
| abi.encodePacked( | ||
| mainnet | ||
| ? "https://scan.layerzero-api.com" // Mainnet | ||
| : "https://scan-testnet.layerzero-api.com", // Testnet | ||
| "/v1/messages/tx/", | ||
| txHash | ||
| ) | ||
| ); | ||
| curlCommand[4] = "-H 'accept: application/json'"; | ||
|
|
||
| // Execute the curl command | ||
| bytes memory result = vm.ffi(curlCommand); | ||
|
|
||
| // Convert the result to a string | ||
| string memory json = string(result); | ||
|
|
||
| // Read the sender chain | ||
| string memory senderChain = json.readString(".data[0].pathway.sender.chain"); | ||
|
|
||
| // Read the destination chain | ||
| string memory destinationChain = json.readString(".data[0].pathway.receiver.chain"); | ||
|
|
||
| // Read the sender address | ||
| bytes32 senderBytes32; | ||
| string memory senderAddressStr = json.readString(".data[0].pathway.sender.address"); | ||
| if (keccak256(bytes(senderChain)) == keccak256(bytes("solana"))) { | ||
| // If the chain is Solana, decode the Base58 address | ||
| bytes memory decodedAddress = senderAddressStr.base58ToHex(); | ||
|
|
||
| // Ensure the decoded address is 32 bytes long | ||
| require(decodedAddress.length == 32, "Decoded address must be 32 bytes"); | ||
| senderBytes32 = bytes32(decodedAddress); | ||
| } else { | ||
| // Otherwise, read the address directly and convert to bytes32 | ||
| address senderAddress = json.readAddress(".data[0].pathway.sender.address"); | ||
| senderBytes32 = addressToBytes32(senderAddress); | ||
| } | ||
| console.log("Sender: %s (%s)", senderAddressStr, senderChain); | ||
|
|
||
| // Read the receiver address | ||
| address receiver = json.readAddress(".data[0].pathway.receiver.address"); | ||
| console.log("Receiver: %s (%s)", receiver, destinationChain); | ||
|
|
||
| // Read the nonce | ||
| uint64 nonce = uint64(json.readUint(".data[0].pathway.nonce")); | ||
| console.log("Nonce:", nonce); | ||
|
|
||
| // Read the transaction hash | ||
| string memory fetchedTxHash = json.readString(".data[0].source.tx.txHash"); | ||
| console.log("Source Transaction Hash:", fetchedTxHash); | ||
|
|
||
| // Read other fields from the JSON | ||
| uint32 srcEid = uint32(json.readUint(".data[0].pathway.srcEid")); | ||
| bytes32 guid = json.readBytes32(".data[0].guid"); | ||
| bytes memory payload = json.readBytes(".data[0].source.tx.payload"); | ||
|
|
||
| // Construct the Origin struct | ||
| Origin memory origin = Origin({ | ||
| srcEid: srcEid, | ||
| sender: senderBytes32, // Use the bytes32 sender | ||
| nonce: nonce | ||
| }); | ||
| bytes memory extraData = ""; | ||
|
|
||
| // Simulate the lzReceive function | ||
| vm.startBroadcast(); | ||
| IOAppCore(receiver).endpoint().lzReceive(origin, receiver, guid, payload, extraData); | ||
| vm.stopBroadcast(); | ||
| } | ||
|
|
||
| // Helper function to convert address to bytes32 | ||
| function addressToBytes32(address _addr) internal pure returns (bytes32) { | ||
| return bytes32(uint256(uint160(_addr))); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.